@malloydata/cli 0.0.53 → 0.0.54-next.2026.5.1.cb0227a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +639 -481
- package/dist/index.js +2 -2
- package/dist/skills/log-analysis-to-notebook.md +98 -0
- package/dist/skills/malloy-language-reference.md +528 -0
- package/dist/skills/writing-malloy-with-mcp.md +84 -0
- package/dist/third_party_notices.txt +7923 -6184
- package/package.json +14 -10
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How to iteratively write Malloy using the MCP tools. Read this once; it describes the tool surface and the compile→run loop.
|
|
3
|
+
---
|
|
4
|
+
# Writing Malloy with the CLI MCP Server
|
|
5
|
+
|
|
6
|
+
This CLI exposes five tools. "Compile" means parse + typecheck + build the model — the successful output is a **structured description** of what's in the source, not just SQL. "Run" means actually execute and return rows.
|
|
7
|
+
|
|
8
|
+
## Tools
|
|
9
|
+
|
|
10
|
+
| Tool | Input | What it does |
|
|
11
|
+
|-----------------|----------------------------------------|--------------------------------------------------------------------------------|
|
|
12
|
+
| `compile_file` | `{ uri, expand? }` | Fetch+compile a .malloy file; returns structured model with problems[]. |
|
|
13
|
+
| `compile` | `{ source, base_uri?, expand? }` | Same, on an inline source string. |
|
|
14
|
+
| `run_file` | `{ uri, name?, index? }` | Execute one run: from a file. `name` wins over `index`; else last run:. |
|
|
15
|
+
| `run` | `{ source, base_uri? }` | Execute the final run: from an inline source. |
|
|
16
|
+
| `list_runs` | `{ uri }` | Cheap discovery: runnable run: + named queries, no model serialization. |
|
|
17
|
+
|
|
18
|
+
Every tool returns a uniform `problems[]` with `{ severity, message, code, uri?, line, column, endLine?, endColumn? }`. Compile errors, import-resolution errors, and runtime SQL errors all use this shape.
|
|
19
|
+
|
|
20
|
+
## Compile result shape
|
|
21
|
+
|
|
22
|
+
```jsonc
|
|
23
|
+
{
|
|
24
|
+
"ok": true,
|
|
25
|
+
"model": {
|
|
26
|
+
"rootUri": "file:///.../flights.malloy",
|
|
27
|
+
"annotations": ["## ..."], // top-level model annotations
|
|
28
|
+
"sources": [
|
|
29
|
+
{
|
|
30
|
+
"name": "flights",
|
|
31
|
+
"annotations": ["# bar_chart"],
|
|
32
|
+
"location": {...},
|
|
33
|
+
"primaryKey": "id",
|
|
34
|
+
"dimensions": [{ "name", "type", "expression", "annotations", "location" }],
|
|
35
|
+
"measures": [{ "name", "type", "expression", "annotations", "location" }],
|
|
36
|
+
"views": [{ "name", "expression", "annotations", "location" }],
|
|
37
|
+
"joins": [
|
|
38
|
+
// Join to a named source → reference by source_ref:
|
|
39
|
+
{ "name": "carriers", "kind": "join", "relationship": "one", "source_ref": "carriers" },
|
|
40
|
+
// Anonymous record / array → inline fields:
|
|
41
|
+
{ "name": "tags", "kind": "join", "relationship": "many",
|
|
42
|
+
"fields": [{ "name": "each", "kind": "dimension", "type": "string" }] }
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"queries": [{ "name": "top_carriers", "annotations": [...], "location": {...} }],
|
|
47
|
+
"runs": [{ "index": 0, "name": "optional", "sql": "SELECT ...", "annotations": [...] }]
|
|
48
|
+
},
|
|
49
|
+
"problems": []
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Joins are rendered by reference by default.** If you need to know what fields a referenced source has, look it up in the same response's `model.sources[]` by name. Pass `expand: "inline"` if you want the sub-schema duplicated in place.
|
|
54
|
+
|
|
55
|
+
**Scalar arrays** (like `tags: string[]`) render as a join with `relationship: "many"` and a single sub-field called `each`. Write `tags.each` to reference them.
|
|
56
|
+
|
|
57
|
+
## The iteration loop
|
|
58
|
+
|
|
59
|
+
1. Start with `compile_file` to see what's in an existing model. Look at `model.sources[]`, their measures, views, joins.
|
|
60
|
+
2. Draft a query — usually `import "that_file"` plus a new `run:` — and call `compile` on it. If `ok: false`, inspect `problems[]`, fix, repeat. Don't guess syntax — the compiler is ground truth.
|
|
61
|
+
3. When compile is clean, call `run` (or `run_file` if the query is already in a file) to get the rows.
|
|
62
|
+
|
|
63
|
+
## The import pattern
|
|
64
|
+
|
|
65
|
+
When the user has an existing `.malloy` file and wants a new query against it, don't retype their source. Write a small document that imports theirs:
|
|
66
|
+
|
|
67
|
+
```malloy
|
|
68
|
+
import "their_model.malloy"
|
|
69
|
+
|
|
70
|
+
run: their_source -> { ... }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Feed that whole thing to `compile`. Imports resolve against `base_uri` if supplied, otherwise against the inline source's synthetic URL (so imports must be absolute unless `base_uri` is given — usually pass the directory of the target file as `base_uri`).
|
|
74
|
+
|
|
75
|
+
## Common errors and how they're reported
|
|
76
|
+
|
|
77
|
+
- **Unknown field** — check `model.sources[].dimensions` / `.measures` / `.views` / `.joins` for what actually exists. If you see `source_ref`, look up the referenced source in the same response.
|
|
78
|
+
- **Aggregate locality** — `sum(joined.x)` across a join boundary requires explicit locality: `source.sum(joined.x)` or `joined.x.sum()`.
|
|
79
|
+
- **Mixed reduction/projection** — a single stage uses either `group_by:`/`aggregate:` OR `select:`, not both.
|
|
80
|
+
- **Calculation in source** — `calculate:` (window functions) only lives in queries, never in source definitions.
|
|
81
|
+
|
|
82
|
+
## Before writing non-trivial Malloy
|
|
83
|
+
|
|
84
|
+
Pull the `malloy-language-reference` prompt first. The language has real scoping and typing rules that the compiler will enforce; don't guess.
|