dataspring-cli 0.3.0__py3-none-any.whl → 0.4.0__py3-none-any.whl
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.
- cli/_skills/dataspring-author/SKILL.md +80 -1
- cli/_skills/dataspring-consume/SKILL.md +151 -6
- cli/_skills/dataspring-correct/SKILL.md +1 -1
- cli/auth.py +194 -293
- cli/bundled_manifest.py +7 -9
- cli/contract.py +444 -372
- cli/generated.py +322 -466
- cli/main.py +110 -456
- cli/output.py +22 -8
- {dataspring_cli-0.3.0.dist-info → dataspring_cli-0.4.0.dist-info}/METADATA +1 -1
- dataspring_cli-0.4.0.dist-info/RECORD +20 -0
- {dataspring_cli-0.3.0.dist-info → dataspring_cli-0.4.0.dist-info}/WHEEL +1 -1
- settings.py +32 -15
- dataspring_cli-0.3.0.dist-info/RECORD +0 -20
- {dataspring_cli-0.3.0.dist-info → dataspring_cli-0.4.0.dist-info}/entry_points.txt +0 -0
|
@@ -196,9 +196,19 @@ already have, not a sync loop to maintain afterwards.
|
|
|
196
196
|
|
|
197
197
|
That's the contract. Boring, dense, useful.
|
|
198
198
|
|
|
199
|
+
## 8.1 Briefings are boards with a cadence
|
|
200
|
+
|
|
201
|
+
Do not build a second set of rows for a recurring mail. A briefing
|
|
202
|
+
references a board by id, so the board and the mail built from it match
|
|
203
|
+
by construction, and `briefing_edit` `render` records which board
|
|
204
|
+
version produced each issue. Edit the board and the next issue follows.
|
|
205
|
+
`render` answers markdown, never HTML; `commit: true` files the issue
|
|
206
|
+
and is what stops later history columns moving. Rendering and checking
|
|
207
|
+
prose is the consumer's job and is covered in `dataspring-consume`.
|
|
208
|
+
|
|
199
209
|
## 9. Parameter reference
|
|
200
210
|
|
|
201
|
-
<!-- dispatch-params: semantic_model_edit metric_edit import_manifest business_context_edit warehouse_edit datacore_edit datacore_run -->
|
|
211
|
+
<!-- dispatch-params: semantic_model_edit metric_edit board_edit briefing_edit import_manifest business_context_edit warehouse_edit datacore_edit datacore_run -->
|
|
202
212
|
_Generated from the dispatch registry (`GET /api/dispatch`); do not edit by hand. Field descriptions are the models' own, verbatim on every surface._
|
|
203
213
|
|
|
204
214
|
#### `semantic_model_edit`
|
|
@@ -275,6 +285,75 @@ MCP tool `metric_edit`; `POST /api/dispatch/metric_edit`. Edit metrics in the or
|
|
|
275
285
|
| `name` | string | yes | |
|
|
276
286
|
| `updates` | object | yes | The updates whose impact to assess |
|
|
277
287
|
|
|
288
|
+
#### `board_edit`
|
|
289
|
+
|
|
290
|
+
MCP tool `board_edit`; `POST /api/dispatch/board_edit`. Create, change, delete or convert a board. The body is `{"action": {"action": "<verb>", ...}}`, one verb per table below.
|
|
291
|
+
|
|
292
|
+
**`apply`** — Write a whole board: create it, or replace an existing one entirely.
|
|
293
|
+
|
|
294
|
+
| Parameter | Type | Required | Description |
|
|
295
|
+
|---|---|---|---|
|
|
296
|
+
| `document` | object | yes | The whole board document (schemas/board.schema.json): `title`, `sections` of `rows`, and optionally `controls` and `display`. A row is {id, metric, label} plus optional filters, format, good ('up'\|'down'), chart and threshold. `metric` is a manifest metric name or 'qm:<name>' for a quick metric. Layout - pages, column spans, chart types - belongs under `display` and is never structure. |
|
|
297
|
+
| `id` | string | no | Board id to write to. Omit to create one (the document's own `id` is used when it has one). |
|
|
298
|
+
| `expect_version` | integer | no | The board version this edit was written against, from the previous edit's `version` or from read(kind="board"). The write is refused with the current version when it is stale, so two agents editing one board cannot silently overwrite each other. Omit to write without a check. |
|
|
299
|
+
|
|
300
|
+
**`patch`** — Apply a JSON merge patch (RFC 7386: a key set to null is removed) to a stored board, for a small edit that does not need the whole document.
|
|
301
|
+
|
|
302
|
+
| Parameter | Type | Required | Description |
|
|
303
|
+
|---|---|---|---|
|
|
304
|
+
| `id` | string | yes | Board id |
|
|
305
|
+
| `patch` | object | yes | JSON merge patch over the stored board document |
|
|
306
|
+
| `expect_version` | integer | no | The board version this edit was written against, from the previous edit's `version` or from read(kind="board"). The write is refused with the current version when it is stale, so two agents editing one board cannot silently overwrite each other. Omit to write without a check. |
|
|
307
|
+
|
|
308
|
+
**`delete`** — Delete a board. Cannot be undone.
|
|
309
|
+
|
|
310
|
+
| Parameter | Type | Required | Description |
|
|
311
|
+
|---|---|---|---|
|
|
312
|
+
| `id` | string | yes | Board id |
|
|
313
|
+
|
|
314
|
+
**`convert_dashboard`** — Convert one of the organization's dashboards into a board, mechanically: each widget becomes a row, pages and sections become sections, and the grid becomes display hints. The dashboard is left exactly as it was.
|
|
315
|
+
|
|
316
|
+
| Parameter | Type | Required | Description |
|
|
317
|
+
|---|---|---|---|
|
|
318
|
+
| `dashboard_id` | string | yes | The dashboard to convert |
|
|
319
|
+
| `id` | string | no | Board id to write to. Defaults to the dashboard's own id. |
|
|
320
|
+
| `save` | boolean | no, default `True` | False returns the converted board without storing it, to look before committing. |
|
|
321
|
+
|
|
322
|
+
#### `briefing_edit`
|
|
323
|
+
|
|
324
|
+
MCP tool `briefing_edit`; `POST /api/dispatch/briefing_edit`. Create, change, delete or RENDER a briefing. The body is `{"action": {"action": "<verb>", ...}}`, one verb per table below.
|
|
325
|
+
|
|
326
|
+
**`apply`** — Write a whole briefing: create it, or replace an existing one entirely.
|
|
327
|
+
|
|
328
|
+
| Parameter | Type | Required | Description |
|
|
329
|
+
|---|---|---|---|
|
|
330
|
+
| `document` | object | yes | The whole briefing document (schemas/briefing.schema.json): id, name, `board` (a saved board's id, or an inline board document), and the optional cadence, period, narrative, freshness and recipients blocks. `board` is a REFERENCE: edit the board and the next issue follows, and each issue records the board version it was rendered from. |
|
|
331
|
+
| `id` | string | no | Briefing id to write to. Omit to use the document's own `id`. |
|
|
332
|
+
| `expect_version` | integer | no | The version this edit was written against, from the previous edit's `version` or dataspring://briefings/<id>. A concurrent change is refused with the current version instead of overwriting it. |
|
|
333
|
+
|
|
334
|
+
**`patch`** — Apply a JSON merge patch (RFC 7386: a key set to null is removed) to a stored briefing, for a small edit that does not need the whole document.
|
|
335
|
+
|
|
336
|
+
| Parameter | Type | Required | Description |
|
|
337
|
+
|---|---|---|---|
|
|
338
|
+
| `id` | string | yes | Briefing id |
|
|
339
|
+
| `patch` | object | yes | JSON merge patch over the stored briefing document |
|
|
340
|
+
| `expect_version` | integer | no | The version this edit was written against, from the previous edit's `version` or dataspring://briefings/<id>. A concurrent change is refused with the current version instead of overwriting it. |
|
|
341
|
+
|
|
342
|
+
**`delete`** — Delete a briefing definition. Its committed issues are kept: they are the record of what was sent, and deleting the definition unsends nothing.
|
|
343
|
+
|
|
344
|
+
| Parameter | Type | Required | Description |
|
|
345
|
+
|---|---|---|---|
|
|
346
|
+
| `id` | string | yes | Briefing id |
|
|
347
|
+
|
|
348
|
+
**`render`** — Render one issue: a headline, a reason, a view URL, markdown blocks and the structured snapshot. Never HTML.
|
|
349
|
+
|
|
350
|
+
| Parameter | Type | Required | Description |
|
|
351
|
+
|---|---|---|---|
|
|
352
|
+
| `id` | string | no | A saved briefing's id. Give this or `inline`, not both. |
|
|
353
|
+
| `inline` | object | no | A whole briefing document to render without saving it, for iterating on a draft. An inline briefing cannot commit: an issue is filed under a stored briefing. |
|
|
354
|
+
| `period` | string | no | Override the period this issue covers (last_closed_week, last_closed_month, mtd, last_<n>_<grain>, ...). Omit to use the briefing's own, which its cadence implies when it names none. Resolved in the organization's timezone and echoed back with the exact dates. |
|
|
355
|
+
| `commit` | boolean | no, default `False` | True writes the snapshot as an issue, ONCE, under this period's key. Do it when you send: the committed issue is what the next issue's history columns read, so those columns never shift afterwards. A period that already has an issue is left exactly as it is and the answer says so. |
|
|
356
|
+
|
|
278
357
|
#### `import_manifest`
|
|
279
358
|
|
|
280
359
|
MCP tool `import_manifest`; `POST /api/dispatch/import_manifest`. Import a semantic manifest using replace semantics.
|
|
@@ -30,6 +30,8 @@ traces — departing from them produces misleading numbers.
|
|
|
30
30
|
| Read business_context | `dataspring://context` resource | `dataspring business-context get` | `GET /api/context` |
|
|
31
31
|
| Check business_context size | `business_context_edit show_size` | `dataspring business-context size` | (no dedicated route — use `GET /api/context` and measure) |
|
|
32
32
|
| Org's published skill | (this skill, served via SKILL.md) | `dataspring skill instructions consume` | `GET /api/v1/skill/consume/instructions` |
|
|
33
|
+
| Be woken when a number moves | `watch_edit apply` | `dataspring watch_edit apply --document-json @watch.yaml` | `POST /api/dispatch/watch_edit` |
|
|
34
|
+
| List watches | `read(kind="watches")` | (no CLI command yet) | `GET /api/watches` |
|
|
33
35
|
|
|
34
36
|
No catalog is pre-loaded. You are handed NO catalog up front — the catalog
|
|
35
37
|
index (`list_metrics` / `dataspring metrics list` / `GET
|
|
@@ -106,7 +108,17 @@ For any analytical question, in this order:
|
|
|
106
108
|
touches, in ONE call. This is where the authoritative description
|
|
107
109
|
lives: unit, source rollup, standing filter rules, caveats (§3). Read
|
|
108
110
|
it before you query; do not paraphrase from the name or the summary.
|
|
109
|
-
3. **
|
|
111
|
+
3. **Check what THAT metric can be sliced by, before you write a
|
|
112
|
+
`dimensions` / `group_by`** — `read(kind="metric_dimensions", id="<metric>")`
|
|
113
|
+
on MCP, the `dataspring://metrics/{name}/dimensions` resource, or
|
|
114
|
+
`GET /api/metrics/{name}/dimensions`. The index in step 1 lists the
|
|
115
|
+
dimensions the ORG has; a metric can only be sliced by the ones its own
|
|
116
|
+
semantic models join to, and the two sets are not the same. Each entry
|
|
117
|
+
carries the exact name to send, the join path that reaches it, the grains a
|
|
118
|
+
time dimension offers, and a sample of a categorical one's values. Skipping
|
|
119
|
+
this is how a query comes back refused for a dimension that exists in the
|
|
120
|
+
org and not on this metric.
|
|
121
|
+
4. **Query** — only now, with the names and grains you just confirmed.
|
|
110
122
|
|
|
111
123
|
Don't skip step 1: "obvious" metrics like `total_revenue` differ across
|
|
112
124
|
orgs in unit, source, and standing filter rules, and a name matching the
|
|
@@ -449,8 +461,8 @@ entity fact goes in that object's `description` in the dbt YAML;
|
|
|
449
461
|
a cross-cutting organisation fact goes in `business_context`. This table
|
|
450
462
|
answers *whether it's worth capturing*; that rule answers *which document*.
|
|
451
463
|
|
|
452
|
-
Propose the change via `metric_edit` / `semantic_model_edit` (MCP), `dataspring
|
|
453
|
-
`dataspring
|
|
464
|
+
Propose the change via `metric_edit` / `semantic_model_edit` (MCP), `dataspring metric_edit create` /
|
|
465
|
+
`dataspring semantic_model_edit create` (CLI), or the equivalent admin REST routes —
|
|
454
466
|
admin/owner only. Show it first (§8): a `preview` compiles the definition
|
|
455
467
|
and writes nothing, so it needs no consent. What needs the user's yes is
|
|
456
468
|
`create`; never make that change unilaterally.
|
|
@@ -539,6 +551,49 @@ breakdown.
|
|
|
539
551
|
The catalog is only stale if the user pivots to a brand-new
|
|
540
552
|
analytical area; in that case, re-list.
|
|
541
553
|
|
|
554
|
+
## 12.1 Do not poll. Ask to be woken.
|
|
555
|
+
|
|
556
|
+
If the task is "tell me when X changes", do not run the same query on a loop.
|
|
557
|
+
Set a **watch** (`watch_edit apply`) and let DataSpring call you: it is the
|
|
558
|
+
only component that knows when data lands, so it evaluates the condition after
|
|
559
|
+
the run that could change it and posts to your webhook.
|
|
560
|
+
|
|
561
|
+
A watch is one board row, one condition, one callback. The condition is not an
|
|
562
|
+
expression — it is one of three shapes, all of them the same rules a
|
|
563
|
+
`board_fetch` answer already reports:
|
|
564
|
+
|
|
565
|
+
```yaml
|
|
566
|
+
id: revenue_odd
|
|
567
|
+
title: Weekly revenue moved oddly
|
|
568
|
+
board_id: weekly # or an inline `board:` document for a row that exists only to be watched
|
|
569
|
+
row: rev
|
|
570
|
+
period: last_closed_week
|
|
571
|
+
compare_to: previous_period
|
|
572
|
+
condition: {kind: notable} # any notability rule
|
|
573
|
+
# condition: {kind: notable, rules: [volatility, sign_change]} # only these
|
|
574
|
+
# condition: {kind: threshold, value: 0.3, direction: below} # stay below 0.3
|
|
575
|
+
# condition: {kind: direction, direction: down, min_change_pct: 0.1}
|
|
576
|
+
delivery: {kind: webhook, url: "https://hooks.example.com/..."}
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
Three things to know before you write one:
|
|
580
|
+
|
|
581
|
+
- **It fires on the edge, not every run.** Once it has fired it stays quiet
|
|
582
|
+
until an evaluation finds the condition no longer met. Do not expect one
|
|
583
|
+
message per run, and do not write a second watch to "confirm" the first.
|
|
584
|
+
- **The callback is signed and you have to verify it.** The answer to a
|
|
585
|
+
create carries a one-time link; open it once and put the secret in your
|
|
586
|
+
receiver. Every request then carries `X-DataSpring-Timestamp` and
|
|
587
|
+
`X-DataSpring-Signature: v1=<hex>`, where the hex is HMAC-SHA256 over
|
|
588
|
+
`v1:<timestamp>:<the raw body>`. Compare it in constant time and refuse a
|
|
589
|
+
timestamp more than a few minutes old.
|
|
590
|
+
- **The URL must be public HTTPS.** Loopback, private, link-local and cloud
|
|
591
|
+
metadata addresses are refused when the watch is written and again against
|
|
592
|
+
what the name resolves to at delivery time, and no redirect is followed.
|
|
593
|
+
|
|
594
|
+
The payload tells you what the row did and gives you a link. What to say
|
|
595
|
+
about it, and to whom, is yours.
|
|
596
|
+
|
|
542
597
|
## 13. The org's `business_context` document
|
|
543
598
|
|
|
544
599
|
Cross-cutting org orientation lives in `business_context` — what
|
|
@@ -558,9 +613,31 @@ manifest workflow), same trust level.
|
|
|
558
613
|
That's the working agreement. Same principles, three surfaces —
|
|
559
614
|
do this and the answers will be right.
|
|
560
615
|
|
|
561
|
-
## 14.
|
|
562
|
-
|
|
563
|
-
|
|
616
|
+
## 14. Briefings: render, write, verify, send
|
|
617
|
+
|
|
618
|
+
A **briefing** is a board plus a cadence. You render it; you deliver it.
|
|
619
|
+
|
|
620
|
+
1. `briefing_edit` `render` answers markdown that leads with the answer — a
|
|
621
|
+
`headline` saying whether the period is normal, a `reason` naming what
|
|
622
|
+
moved and the rule it broke, and a `view_url` the reader can open — then
|
|
623
|
+
`blocks[]` you can send whole or recombine, then the structured `snapshot`.
|
|
624
|
+
It never returns HTML; convert at the point of sending if you need it.
|
|
625
|
+
2. Write the prose yourself unless the briefing asks DataSpring to write it.
|
|
626
|
+
Quote numbers from the snapshot, not from your own arithmetic.
|
|
627
|
+
3. **Check it with `verify_numbers` before you send.** Pass the text and the
|
|
628
|
+
`snapshot_id` the render returned. It answers with every number the
|
|
629
|
+
snapshot does not support, in Danish and English formats, and lists dates,
|
|
630
|
+
years and counts of periods under `ignored` rather than flagging them. A
|
|
631
|
+
high-confidence mismatch means the sentence is wrong, not that the tool is
|
|
632
|
+
fussy: fix the sentence.
|
|
633
|
+
4. Render again with `commit: true` when you actually send. That files the
|
|
634
|
+
issue, and the next issue's history columns read it instead of re-querying,
|
|
635
|
+
so a column a reader has already seen cannot move afterwards. Commit when
|
|
636
|
+
you send and not before.
|
|
637
|
+
|
|
638
|
+
## 15. Parameter reference
|
|
639
|
+
|
|
640
|
+
<!-- dispatch-params: query_metrics board_fetch explain_query run_sql briefing_edit verify_numbers update_context quick_metric_edit learned_edit verified_query_edit business_context_edit -->
|
|
564
641
|
_Generated from the dispatch registry (`GET /api/dispatch`); do not edit by hand. Field descriptions are the models' own, verbatim on every surface._
|
|
565
642
|
|
|
566
643
|
#### `query_metrics`
|
|
@@ -574,13 +651,35 @@ MCP tool `query_metrics`; `POST /api/dispatch/query_metrics`. Fetch metric data
|
|
|
574
651
|
| `grain` | string | no | Time granularity: 'day', 'week', 'month', 'quarter', or 'year' |
|
|
575
652
|
| `start_date` | string | no | Start date in YYYY-MM-DD format |
|
|
576
653
|
| `end_date` | string | no | End date in YYYY-MM-DD format |
|
|
654
|
+
| `period` | string | no | A named period, resolved server-side in the organization's timezone and echoed back on the answer as `period` with the exact start and end dates it meant: last_closed_day, last_closed_week, last_closed_month, last_closed_quarter, last_closed_year (the most recent whole one that has ended); wtd, mtd, qtd, ytd (the current one so far, still open); or last_<n>_<grain> such as last_13_week (the n most recently closed periods as one window). Use this instead of start_date/end_date whenever the question is relative, so the dates are DataSpring's and not a guess about which timezone today is in. Ignored when start_date and end_date are both given. |
|
|
577
655
|
| `limit` | integer | no | Maximum number of rows to return |
|
|
578
656
|
| `order_by` | string | no | Column to sort by, append ' desc' for descending (e.g., 'total_revenue desc') |
|
|
579
657
|
| `where` | list of string | no | Row filters in MetricFlow's constraint syntax, one string each, e.g. "{{ Dimension('customer__segment') }} NOT IN ('Direct')". Use qualified names from dataspring://dimensions - an unresolvable name comes back as an error whose suggestion names the qualified form. `where` decides WHICH ROWS the numbers cover; `dimensions` breaks the numbers OUT by a column; send both for a breakdown of a filtered slice. A `where` on a dimension also overrides the user's standing filter on that same dimension for this call. |
|
|
580
658
|
| `warehouse` | string | no | Which of the org's warehouses to run against - an id from dataspring://warehouses ('managed', 'external', ...). Omit for the active one. During a migration ask both and compare. |
|
|
659
|
+
| `compare_to` | one of `previous_period`, `same_period_last_year` | no | Compare the window against the one before it (previous_period, stepped back by whole calendar periods when the window is whole ones) or the same window a year earlier (same_period_last_year). The deltas come back BESIDE the values - each metric column gains <metric>__previous, <metric>__delta and <metric>__delta_pct - so there is no second result set to line up and no arithmetic to do. `comparison_period` says which window they were measured against. |
|
|
581
660
|
| `suggest_visualization` | boolean | no, default `False` | Also return a suggested visualization type for the result. |
|
|
582
661
|
| `format` | one of `json`, `csv` | no, default `json` | 'json' (default) answers rows in `data`; 'csv' answers the same result as one CSV document in `content` (header row first) for a file or a spreadsheet, with `columns` and `row_count` alongside. |
|
|
583
662
|
|
|
663
|
+
#### `board_fetch`
|
|
664
|
+
|
|
665
|
+
MCP tool `board_fetch`; `POST /api/dispatch/board_fetch`. Run every row of a board in one call and answer salience first.
|
|
666
|
+
|
|
667
|
+
| Parameter | Type | Required | Description |
|
|
668
|
+
|---|---|---|---|
|
|
669
|
+
| `board_id` | string | no | A saved board's id. Give this or `inline`, not both. |
|
|
670
|
+
| `inline` | object | no | A whole board document to run without saving it (schemas/board.schema.json). This is how to ask several unrelated questions in one call: put each one in its own row. |
|
|
671
|
+
| `period` | string | no | A named period, resolved server-side in the organization's timezone and echoed back on the answer as `period` with the exact start and end dates it meant: last_closed_day, last_closed_week, last_closed_month, last_closed_quarter, last_closed_year (the most recent whole one that has ended); wtd, mtd, qtd, ytd (the current one so far, still open); or last_<n>_<grain> such as last_13_week (the n most recently closed periods as one window). Use this instead of start_date/end_date whenever the question is relative, so the dates are DataSpring's and not a guess about which timezone today is in. Ignored when start_date and end_date are both given. |
|
|
672
|
+
| `grain` | one of `day`, `week`, `month`, `quarter`, `year` | no | Bucket grain for each row's history. Defaults to the period's own grain. |
|
|
673
|
+
| `start_date` | string | no | Start date in YYYY-MM-DD format, instead of a named period |
|
|
674
|
+
| `end_date` | string | no | End date in YYYY-MM-DD format, instead of a named period |
|
|
675
|
+
| `compare_to` | one of `previous_period`, `same_period_last_year` | no | Compare the window against the one before it (previous_period, stepped back by whole calendar periods when the window is whole ones) or the same window a year earlier (same_period_last_year). The deltas come back BESIDE the values - each metric column gains <metric>__previous, <metric>__delta and <metric>__delta_pct - so there is no second result set to line up and no arithmetic to do. `comparison_period` says which window they were measured against. |
|
|
676
|
+
| `detail` | one of `salient`, `full` | no, default `salient` | 'salient' (default) answers EVERY row compactly - value, delta, and whether it is notable - and adds the full detail (history, sparkline, receipt, freshness, which rule fired) only for the rows that are notable plus any named in `rows`. 'full' answers everything for every row, for an export or a spreadsheet. |
|
|
677
|
+
| `rows` | list of string | no | Row ids to return in full detail whether or not they are notable. |
|
|
678
|
+
| `history` | integer | no, default `13` | How many periods of history to fetch per row, for the sparkline and the volatility measure. |
|
|
679
|
+
| `format` | one of `json`, `markdown`, `csv` | no, default `json` | 'json' (default) answers the structured result; 'markdown' adds one markdown document in `content`, leading with what moved and then a table per section, ready to paste into a chat, a document or a terminal; 'csv' adds one row per board row in `content`. |
|
|
680
|
+
| `locale` | one of `en`, `da` | no, default `en` | Number formatting for the `formatted` fields: 'en' (1,234.5) or 'da' (1.234,5). |
|
|
681
|
+
| `warehouse` | string | no | Which of the org's warehouses to run against. Omit for the active one. |
|
|
682
|
+
|
|
584
683
|
#### `explain_query`
|
|
585
684
|
|
|
586
685
|
MCP tool `explain_query`; `POST /api/dispatch/explain_query`. Show what a query computes without running it: the resolved metrics and dimensions, the effective time window, the filters (including any standing preference folded in) and the compiled SQL. Use it when the user asks what you actually computed, disputes a number, or before proposing a correction. ``warehouse`` picks one of the org's warehouses; omit it for the active one.
|
|
@@ -592,6 +691,7 @@ MCP tool `explain_query`; `POST /api/dispatch/explain_query`. Show what a query
|
|
|
592
691
|
| `grain` | string | no | Time granularity: 'day', 'week', 'month', 'quarter', or 'year' |
|
|
593
692
|
| `start_date` | string | no | Start date in YYYY-MM-DD format |
|
|
594
693
|
| `end_date` | string | no | End date in YYYY-MM-DD format |
|
|
694
|
+
| `period` | string | no | A named period, resolved server-side in the organization's timezone and echoed back on the answer as `period` with the exact start and end dates it meant: last_closed_day, last_closed_week, last_closed_month, last_closed_quarter, last_closed_year (the most recent whole one that has ended); wtd, mtd, qtd, ytd (the current one so far, still open); or last_<n>_<grain> such as last_13_week (the n most recently closed periods as one window). Use this instead of start_date/end_date whenever the question is relative, so the dates are DataSpring's and not a guess about which timezone today is in. Ignored when start_date and end_date are both given. |
|
|
595
695
|
| `limit` | integer | no | Maximum number of rows to return |
|
|
596
696
|
| `order_by` | string | no | Column to sort by, append ' desc' for descending (e.g., 'total_revenue desc') |
|
|
597
697
|
| `where` | list of string | no | Row filters in MetricFlow's constraint syntax, one string each, e.g. "{{ Dimension('customer__segment') }} NOT IN ('Direct')". Use qualified names from dataspring://dimensions - an unresolvable name comes back as an error whose suggestion names the qualified form. `where` decides WHICH ROWS the numbers cover; `dimensions` breaks the numbers OUT by a column; send both for a breakdown of a filtered slice. A `where` on a dimension also overrides the user's standing filter on that same dimension for this call. |
|
|
@@ -609,6 +709,51 @@ MCP tool `run_sql`; `POST /api/dispatch/run_sql`. Run ONE read-only SQL statemen
|
|
|
609
709
|
| `format` | one of `json`, `csv`, `markdown` | no, default `json` | 'json' answers rows in `data`; 'csv' or 'markdown' answer one document in `content`. |
|
|
610
710
|
| `dry_run` | boolean | no, default `False` | Only estimate the bytes the statement would process (and check it parses); run nothing. |
|
|
611
711
|
|
|
712
|
+
#### `briefing_edit`
|
|
713
|
+
|
|
714
|
+
MCP tool `briefing_edit`; `POST /api/dispatch/briefing_edit`. Create, change, delete or RENDER a briefing. The body is `{"action": {"action": "<verb>", ...}}`, one verb per table below.
|
|
715
|
+
|
|
716
|
+
**`apply`** — Write a whole briefing: create it, or replace an existing one entirely.
|
|
717
|
+
|
|
718
|
+
| Parameter | Type | Required | Description |
|
|
719
|
+
|---|---|---|---|
|
|
720
|
+
| `document` | object | yes | The whole briefing document (schemas/briefing.schema.json): id, name, `board` (a saved board's id, or an inline board document), and the optional cadence, period, narrative, freshness and recipients blocks. `board` is a REFERENCE: edit the board and the next issue follows, and each issue records the board version it was rendered from. |
|
|
721
|
+
| `id` | string | no | Briefing id to write to. Omit to use the document's own `id`. |
|
|
722
|
+
| `expect_version` | integer | no | The version this edit was written against, from the previous edit's `version` or dataspring://briefings/<id>. A concurrent change is refused with the current version instead of overwriting it. |
|
|
723
|
+
|
|
724
|
+
**`patch`** — Apply a JSON merge patch (RFC 7386: a key set to null is removed) to a stored briefing, for a small edit that does not need the whole document.
|
|
725
|
+
|
|
726
|
+
| Parameter | Type | Required | Description |
|
|
727
|
+
|---|---|---|---|
|
|
728
|
+
| `id` | string | yes | Briefing id |
|
|
729
|
+
| `patch` | object | yes | JSON merge patch over the stored briefing document |
|
|
730
|
+
| `expect_version` | integer | no | The version this edit was written against, from the previous edit's `version` or dataspring://briefings/<id>. A concurrent change is refused with the current version instead of overwriting it. |
|
|
731
|
+
|
|
732
|
+
**`delete`** — Delete a briefing definition. Its committed issues are kept: they are the record of what was sent, and deleting the definition unsends nothing.
|
|
733
|
+
|
|
734
|
+
| Parameter | Type | Required | Description |
|
|
735
|
+
|---|---|---|---|
|
|
736
|
+
| `id` | string | yes | Briefing id |
|
|
737
|
+
|
|
738
|
+
**`render`** — Render one issue: a headline, a reason, a view URL, markdown blocks and the structured snapshot. Never HTML.
|
|
739
|
+
|
|
740
|
+
| Parameter | Type | Required | Description |
|
|
741
|
+
|---|---|---|---|
|
|
742
|
+
| `id` | string | no | A saved briefing's id. Give this or `inline`, not both. |
|
|
743
|
+
| `inline` | object | no | A whole briefing document to render without saving it, for iterating on a draft. An inline briefing cannot commit: an issue is filed under a stored briefing. |
|
|
744
|
+
| `period` | string | no | Override the period this issue covers (last_closed_week, last_closed_month, mtd, last_<n>_<grain>, ...). Omit to use the briefing's own, which its cadence implies when it names none. Resolved in the organization's timezone and echoed back with the exact dates. |
|
|
745
|
+
| `commit` | boolean | no, default `False` | True writes the snapshot as an issue, ONCE, under this period's key. Do it when you send: the committed issue is what the next issue's history columns read, so those columns never shift afterwards. A period that already has an issue is left exactly as it is and the answer says so. |
|
|
746
|
+
|
|
747
|
+
#### `verify_numbers`
|
|
748
|
+
|
|
749
|
+
MCP tool `verify_numbers`; `POST /api/dispatch/verify_numbers`. Check every number in a piece of prose against a briefing snapshot.
|
|
750
|
+
|
|
751
|
+
| Parameter | Type | Required | Description |
|
|
752
|
+
|---|---|---|---|
|
|
753
|
+
| `text` | string | yes | The prose to check. Markdown is fine; code spans and URLs are skipped. |
|
|
754
|
+
| `snapshot_id` | string | no | A committed issue's snapshot id, as render returns it ('<briefing_id>:<period_key>'). Give this or `snapshot`, not both. |
|
|
755
|
+
| `snapshot` | object | no | The `snapshot` block a render returned, for prose written against an issue that has not been committed. Give this or `snapshot_id`. |
|
|
756
|
+
|
|
612
757
|
#### `update_context`
|
|
613
758
|
|
|
614
759
|
MCP tool `update_context`; `POST /api/dispatch/update_context`. Update user preferences (merge, not replace).
|
|
@@ -36,7 +36,7 @@ no data. Explaining a null is not an answer.
|
|
|
36
36
|
| Region, dbt layout, project-level operational pointers | `business_context` |
|
|
37
37
|
| Findings, analysis results, history | NOT in the context layer at all |
|
|
38
38
|
| Per-metric definition logic | NOT in context — lives in the dbt model SQL |
|
|
39
|
-
| The user's own standing intent ("always exclude Direct for me") | A personal preference, via `
|
|
39
|
+
| The user's own standing intent ("always exclude Direct for me") | A personal preference, via `update_context` |
|
|
40
40
|
| A question and the query that correctly answers it, confirmed by the user | `verified_query_edit` record, scope `user` |
|
|
41
41
|
|
|
42
42
|
A verified query is scope `org` only on an admin's say-so. When torn between
|