@oxy-hq/cli 0.1.0

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 (39) hide show
  1. package/README.md +163 -0
  2. package/dist/main.mjs +6688 -0
  3. package/dist/main.mjs.map +1 -0
  4. package/dist/mcp-VdontkUr.mjs +316 -0
  5. package/dist/mcp-VdontkUr.mjs.map +1 -0
  6. package/json-schemas/agent-test.json +104 -0
  7. package/json-schemas/agentic.json +406 -0
  8. package/json-schemas/app.json +1884 -0
  9. package/json-schemas/config.json +2215 -0
  10. package/json-schemas/flow-test.json +124 -0
  11. package/json-schemas/global-semantics.json +782 -0
  12. package/json-schemas/workflow.json +1907 -0
  13. package/package.json +65 -0
  14. package/skills/oxy-airway-pipelines/SKILL.md +338 -0
  15. package/skills/oxy-automations/SKILL.md +67 -0
  16. package/skills/oxy-cli/SKILL.md +134 -0
  17. package/skills/oxy-custom-apps/SKILL.md +330 -0
  18. package/skills/oxy-data-architecture/SKILL.md +225 -0
  19. package/skills/oxy-semantic-modeling/SKILL.md +216 -0
  20. package/template/.gitattributes +2 -0
  21. package/template/.github/scripts/ci-publish.sh +77 -0
  22. package/template/.github/scripts/discover-apps.sh +175 -0
  23. package/template/.github/scripts/publish-env.sh +55 -0
  24. package/template/.github/workflows/publish.yaml +653 -0
  25. package/template/.github/workflows/validate.yaml +264 -0
  26. package/template/.nvmrc +1 -0
  27. package/template/.oxyc-managed +297 -0
  28. package/template/README.md +414 -0
  29. package/template/_gitignore +32 -0
  30. package/template/apps/.gitkeep +0 -0
  31. package/template/config.yml +53 -0
  32. package/template/memory/.gitkeep +0 -0
  33. package/template/package.json +17 -0
  34. package/template/pipelines/.gitkeep +0 -0
  35. package/template/pnpm-workspace.yaml +32 -0
  36. package/template/scripts/dev.sh +443 -0
  37. package/template/semantics/topics/.gitkeep +0 -0
  38. package/template/semantics/views/.gitkeep +0 -0
  39. package/template/workflows/.gitkeep +0 -0
@@ -0,0 +1,1884 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "AppConfig",
4
+ "type": "object",
5
+ "required": [
6
+ "display",
7
+ "tasks"
8
+ ],
9
+ "properties": {
10
+ "controls": {
11
+ "description": "Interactive controls (dropdowns, toggles, date pickers) whose values are injected into task Jinja templates as `{{ controls.<name> }}`.",
12
+ "default": [],
13
+ "type": "array",
14
+ "items": {
15
+ "$ref": "#/definitions/ControlConfig"
16
+ }
17
+ },
18
+ "description": {
19
+ "description": "Optional description of the app.",
20
+ "default": "",
21
+ "type": "string"
22
+ },
23
+ "display": {
24
+ "description": "display blocks to render the app",
25
+ "type": "array",
26
+ "items": {
27
+ "$ref": "#/definitions/Display"
28
+ }
29
+ },
30
+ "published": {
31
+ "description": "When false (default), the app is treated as a draft and hidden from the left sidebar. Authors can still open, edit, and run it from the IDE. Flip to true to make the app visible to consumers.",
32
+ "default": false,
33
+ "type": "boolean"
34
+ },
35
+ "tasks": {
36
+ "description": "tasks to prepare the data for the app",
37
+ "type": "array",
38
+ "items": {
39
+ "$ref": "#/definitions/Task"
40
+ }
41
+ },
42
+ "title": {
43
+ "description": "Human-friendly title shown in dashboard listings. When unset, callers fall back to a humanized form of the filename-derived name.",
44
+ "type": [
45
+ "string",
46
+ "null"
47
+ ]
48
+ }
49
+ },
50
+ "additionalProperties": false,
51
+ "definitions": {
52
+ "AppTaskMode": {
53
+ "description": "Where a task is executed when used inside an app with interactive controls. `client` (default) — the frontend re-runs the SQL directly in DuckDB WASM on every control change; no server round-trip required. `server` — the server executes the task on every control change (required for tasks that query external databases like Snowflake or BigQuery).",
54
+ "type": "string",
55
+ "enum": [
56
+ "client",
57
+ "server"
58
+ ]
59
+ },
60
+ "Condition": {
61
+ "type": "object",
62
+ "required": [
63
+ "if",
64
+ "tasks"
65
+ ],
66
+ "properties": {
67
+ "if": {
68
+ "type": "string"
69
+ },
70
+ "tasks": {
71
+ "type": "array",
72
+ "items": {
73
+ "$ref": "#/definitions/Task"
74
+ }
75
+ }
76
+ }
77
+ },
78
+ "ControlConfig": {
79
+ "type": "object",
80
+ "required": [
81
+ "name",
82
+ "type"
83
+ ],
84
+ "properties": {
85
+ "default": {
86
+ "description": "Default value injected into Jinja context on initial load.",
87
+ "default": null
88
+ },
89
+ "label": {
90
+ "default": null,
91
+ "type": [
92
+ "string",
93
+ "null"
94
+ ]
95
+ },
96
+ "name": {
97
+ "type": "string"
98
+ },
99
+ "options": {
100
+ "description": "Static list of options (used when source is not set).",
101
+ "default": null,
102
+ "type": [
103
+ "array",
104
+ "null"
105
+ ],
106
+ "items": true
107
+ },
108
+ "source": {
109
+ "description": "Task name whose first column populates dropdown options dynamically.",
110
+ "default": null,
111
+ "type": [
112
+ "string",
113
+ "null"
114
+ ]
115
+ },
116
+ "type": {
117
+ "$ref": "#/definitions/ControlType"
118
+ }
119
+ }
120
+ },
121
+ "ControlType": {
122
+ "type": "string",
123
+ "enum": [
124
+ "select",
125
+ "toggle",
126
+ "date"
127
+ ]
128
+ },
129
+ "Display": {
130
+ "oneOf": [
131
+ {
132
+ "type": "object",
133
+ "required": [
134
+ "content",
135
+ "type"
136
+ ],
137
+ "properties": {
138
+ "content": {
139
+ "type": "string"
140
+ },
141
+ "type": {
142
+ "type": "string",
143
+ "enum": [
144
+ "markdown"
145
+ ]
146
+ }
147
+ }
148
+ },
149
+ {
150
+ "type": "object",
151
+ "required": [
152
+ "data",
153
+ "type",
154
+ "x",
155
+ "y"
156
+ ],
157
+ "properties": {
158
+ "data": {
159
+ "description": "reference data output from a table using table name",
160
+ "type": "string"
161
+ },
162
+ "series": {
163
+ "type": [
164
+ "string",
165
+ "null"
166
+ ]
167
+ },
168
+ "title": {
169
+ "type": [
170
+ "string",
171
+ "null"
172
+ ]
173
+ },
174
+ "type": {
175
+ "type": "string",
176
+ "enum": [
177
+ "line_chart"
178
+ ]
179
+ },
180
+ "x": {
181
+ "type": "string"
182
+ },
183
+ "x_axis_label": {
184
+ "type": [
185
+ "string",
186
+ "null"
187
+ ]
188
+ },
189
+ "y": {
190
+ "type": "string"
191
+ },
192
+ "y_axis_label": {
193
+ "type": [
194
+ "string",
195
+ "null"
196
+ ]
197
+ },
198
+ "y_format": {
199
+ "description": "Optional formatting applied to the y-axis labels and tooltip values. Use `currency` for monetary measures. Unset renders raw numbers.",
200
+ "anyOf": [
201
+ {
202
+ "$ref": "#/definitions/DisplayFormat"
203
+ },
204
+ {
205
+ "type": "null"
206
+ }
207
+ ]
208
+ }
209
+ }
210
+ },
211
+ {
212
+ "type": "object",
213
+ "required": [
214
+ "data",
215
+ "name",
216
+ "type",
217
+ "value"
218
+ ],
219
+ "properties": {
220
+ "data": {
221
+ "description": "reference data output from a table using table name",
222
+ "type": "string"
223
+ },
224
+ "name": {
225
+ "type": "string"
226
+ },
227
+ "title": {
228
+ "type": [
229
+ "string",
230
+ "null"
231
+ ]
232
+ },
233
+ "type": {
234
+ "type": "string",
235
+ "enum": [
236
+ "pie_chart"
237
+ ]
238
+ },
239
+ "value": {
240
+ "type": "string"
241
+ },
242
+ "value_format": {
243
+ "description": "Optional formatting applied to the slice value in the tooltip. Use `currency` for monetary measures. Unset renders raw numbers.",
244
+ "anyOf": [
245
+ {
246
+ "$ref": "#/definitions/DisplayFormat"
247
+ },
248
+ {
249
+ "type": "null"
250
+ }
251
+ ]
252
+ }
253
+ }
254
+ },
255
+ {
256
+ "type": "object",
257
+ "required": [
258
+ "data",
259
+ "type",
260
+ "x",
261
+ "y"
262
+ ],
263
+ "properties": {
264
+ "data": {
265
+ "description": "reference data output from a table using table name",
266
+ "type": "string"
267
+ },
268
+ "series": {
269
+ "type": [
270
+ "string",
271
+ "null"
272
+ ]
273
+ },
274
+ "title": {
275
+ "type": [
276
+ "string",
277
+ "null"
278
+ ]
279
+ },
280
+ "type": {
281
+ "type": "string",
282
+ "enum": [
283
+ "bar_chart"
284
+ ]
285
+ },
286
+ "x": {
287
+ "type": "string"
288
+ },
289
+ "y": {
290
+ "type": "string"
291
+ },
292
+ "y_format": {
293
+ "description": "Optional formatting applied to the y-axis labels and tooltip values. Use `currency` for monetary measures. Unset renders raw numbers.",
294
+ "anyOf": [
295
+ {
296
+ "$ref": "#/definitions/DisplayFormat"
297
+ },
298
+ {
299
+ "type": "null"
300
+ }
301
+ ]
302
+ }
303
+ }
304
+ },
305
+ {
306
+ "type": "object",
307
+ "required": [
308
+ "data",
309
+ "type"
310
+ ],
311
+ "properties": {
312
+ "data": {
313
+ "type": "string"
314
+ },
315
+ "formats": {
316
+ "description": "Optional per-column formatting. Keys are the output column names as they appear in the task result (e.g. `oxymart__total_weekly_sales` for semantic_query tasks, which join view + field with `__`). Columns omitted from the map fall back to the default numeric formatter.",
317
+ "type": [
318
+ "object",
319
+ "null"
320
+ ],
321
+ "additionalProperties": {
322
+ "$ref": "#/definitions/DisplayFormat"
323
+ }
324
+ },
325
+ "title": {
326
+ "type": [
327
+ "string",
328
+ "null"
329
+ ]
330
+ },
331
+ "type": {
332
+ "type": "string",
333
+ "enum": [
334
+ "table"
335
+ ]
336
+ }
337
+ }
338
+ },
339
+ {
340
+ "type": "object",
341
+ "required": [
342
+ "children",
343
+ "type"
344
+ ],
345
+ "properties": {
346
+ "children": {
347
+ "description": "Child display blocks rendered side-by-side in a grid row.",
348
+ "type": "array",
349
+ "items": {
350
+ "$ref": "#/definitions/Display"
351
+ }
352
+ },
353
+ "columns": {
354
+ "description": "Number of equal-width columns; defaults to the number of children.",
355
+ "default": null,
356
+ "type": [
357
+ "integer",
358
+ "null"
359
+ ],
360
+ "format": "uint8",
361
+ "minimum": 0.0
362
+ },
363
+ "type": {
364
+ "type": "string",
365
+ "enum": [
366
+ "row"
367
+ ]
368
+ }
369
+ }
370
+ },
371
+ {
372
+ "description": "A group of controls defined inline in the display list. The backend extracts these items into the controls array before sending to clients.",
373
+ "type": "object",
374
+ "required": [
375
+ "items",
376
+ "type"
377
+ ],
378
+ "properties": {
379
+ "items": {
380
+ "description": "Interactive controls defined inline in the display list.",
381
+ "type": "array",
382
+ "items": {
383
+ "$ref": "#/definitions/ControlConfig"
384
+ }
385
+ },
386
+ "type": {
387
+ "type": "string",
388
+ "enum": [
389
+ "controls"
390
+ ]
391
+ }
392
+ }
393
+ },
394
+ {
395
+ "description": "A single control defined inline in the display list. Because the Display enum uses \"type\" as its discriminant, the control kind is expressed as \"control_type\" instead of \"type\" to avoid a duplicate-key conflict:\n\ndisplay: - type: control name: region control_type: select label: Region options: [All, North, South]",
396
+ "type": "object",
397
+ "required": [
398
+ "control_type",
399
+ "name",
400
+ "type"
401
+ ],
402
+ "properties": {
403
+ "control_type": {
404
+ "$ref": "#/definitions/ControlType"
405
+ },
406
+ "default": {
407
+ "default": null
408
+ },
409
+ "label": {
410
+ "default": null,
411
+ "type": [
412
+ "string",
413
+ "null"
414
+ ]
415
+ },
416
+ "name": {
417
+ "type": "string"
418
+ },
419
+ "options": {
420
+ "default": null,
421
+ "type": [
422
+ "array",
423
+ "null"
424
+ ],
425
+ "items": true
426
+ },
427
+ "source": {
428
+ "default": null,
429
+ "type": [
430
+ "string",
431
+ "null"
432
+ ]
433
+ },
434
+ "type": {
435
+ "type": "string",
436
+ "enum": [
437
+ "control"
438
+ ]
439
+ }
440
+ }
441
+ }
442
+ ]
443
+ },
444
+ "DisplayFormat": {
445
+ "description": "How a numeric value is formatted for display.\n\nUsed on chart axes / tooltips and on individual table columns. When unset, the renderer falls back to its default numeric formatting (trailing zeros stripped for integers, two decimals for floats).",
446
+ "oneOf": [
447
+ {
448
+ "description": "Monetary values — e.g. `$301,397,792.46`. Uses USD by default.",
449
+ "type": "string",
450
+ "enum": [
451
+ "currency"
452
+ ]
453
+ },
454
+ {
455
+ "description": "Percentage values — e.g. `12.5%`. Input is already a percentage (0–100), not a ratio.",
456
+ "type": "string",
457
+ "enum": [
458
+ "percent"
459
+ ]
460
+ },
461
+ {
462
+ "description": "Plain number with thousands separators — e.g. `1,234,567`.",
463
+ "type": "string",
464
+ "enum": [
465
+ "number"
466
+ ]
467
+ }
468
+ ]
469
+ },
470
+ "ExportFormat": {
471
+ "type": "string",
472
+ "enum": [
473
+ "sql",
474
+ "csv",
475
+ "json",
476
+ "txt",
477
+ "docx"
478
+ ]
479
+ },
480
+ "LookerSortField": {
481
+ "description": "A sort field for a Looker query with explicit field name and direction.",
482
+ "type": "object",
483
+ "required": [
484
+ "field"
485
+ ],
486
+ "properties": {
487
+ "direction": {
488
+ "default": "asc",
489
+ "type": "string"
490
+ },
491
+ "field": {
492
+ "type": "string"
493
+ }
494
+ }
495
+ },
496
+ "LoopValues": {
497
+ "anyOf": [
498
+ {
499
+ "type": "string"
500
+ },
501
+ {
502
+ "type": "array",
503
+ "items": true
504
+ }
505
+ ]
506
+ },
507
+ "OrderType": {
508
+ "type": "string",
509
+ "enum": [
510
+ "asc",
511
+ "desc"
512
+ ]
513
+ },
514
+ "PersistToSecret": {
515
+ "description": "Persist a field of an `http_request` JSON response back into a project secret.\n\nThis is the rotating-OAuth-token path: the QuickBooks token-refresh response returns a new `refresh_token`, which we write back to the secret store so the next run starts from the latest value (mirrors the Airway Intuit source).",
516
+ "type": "object",
517
+ "required": [
518
+ "from",
519
+ "name"
520
+ ],
521
+ "properties": {
522
+ "from": {
523
+ "description": "JSON pointer into the parsed response body, e.g. `/refresh_token`.",
524
+ "type": "string"
525
+ },
526
+ "name": {
527
+ "description": "Project secret name to upsert with the extracted value.",
528
+ "type": "string"
529
+ }
530
+ }
531
+ },
532
+ "SemanticFilter": {
533
+ "anyOf": [
534
+ {
535
+ "type": "object",
536
+ "required": [
537
+ "field",
538
+ "op",
539
+ "value"
540
+ ],
541
+ "properties": {
542
+ "field": {
543
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
544
+ "type": "string"
545
+ },
546
+ "op": {
547
+ "type": "string",
548
+ "enum": [
549
+ "eq"
550
+ ]
551
+ },
552
+ "value": {
553
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
554
+ "type": [
555
+ "string",
556
+ "number",
557
+ "boolean",
558
+ "null"
559
+ ]
560
+ }
561
+ }
562
+ },
563
+ {
564
+ "type": "object",
565
+ "required": [
566
+ "field",
567
+ "op",
568
+ "value"
569
+ ],
570
+ "properties": {
571
+ "field": {
572
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
573
+ "type": "string"
574
+ },
575
+ "op": {
576
+ "type": "string",
577
+ "enum": [
578
+ "neq"
579
+ ]
580
+ },
581
+ "value": {
582
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
583
+ "type": [
584
+ "string",
585
+ "number",
586
+ "boolean",
587
+ "null"
588
+ ]
589
+ }
590
+ }
591
+ },
592
+ {
593
+ "type": "object",
594
+ "required": [
595
+ "field",
596
+ "op",
597
+ "value"
598
+ ],
599
+ "properties": {
600
+ "field": {
601
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
602
+ "type": "string"
603
+ },
604
+ "op": {
605
+ "type": "string",
606
+ "enum": [
607
+ "gt"
608
+ ]
609
+ },
610
+ "value": {
611
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
612
+ "type": [
613
+ "string",
614
+ "number",
615
+ "boolean",
616
+ "null"
617
+ ]
618
+ }
619
+ }
620
+ },
621
+ {
622
+ "type": "object",
623
+ "required": [
624
+ "field",
625
+ "op",
626
+ "value"
627
+ ],
628
+ "properties": {
629
+ "field": {
630
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
631
+ "type": "string"
632
+ },
633
+ "op": {
634
+ "type": "string",
635
+ "enum": [
636
+ "gte"
637
+ ]
638
+ },
639
+ "value": {
640
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
641
+ "type": [
642
+ "string",
643
+ "number",
644
+ "boolean",
645
+ "null"
646
+ ]
647
+ }
648
+ }
649
+ },
650
+ {
651
+ "type": "object",
652
+ "required": [
653
+ "field",
654
+ "op",
655
+ "value"
656
+ ],
657
+ "properties": {
658
+ "field": {
659
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
660
+ "type": "string"
661
+ },
662
+ "op": {
663
+ "type": "string",
664
+ "enum": [
665
+ "lt"
666
+ ]
667
+ },
668
+ "value": {
669
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
670
+ "type": [
671
+ "string",
672
+ "number",
673
+ "boolean",
674
+ "null"
675
+ ]
676
+ }
677
+ }
678
+ },
679
+ {
680
+ "type": "object",
681
+ "required": [
682
+ "field",
683
+ "op",
684
+ "value"
685
+ ],
686
+ "properties": {
687
+ "field": {
688
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
689
+ "type": "string"
690
+ },
691
+ "op": {
692
+ "type": "string",
693
+ "enum": [
694
+ "lte"
695
+ ]
696
+ },
697
+ "value": {
698
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
699
+ "type": [
700
+ "string",
701
+ "number",
702
+ "boolean",
703
+ "null"
704
+ ]
705
+ }
706
+ }
707
+ },
708
+ {
709
+ "type": "object",
710
+ "required": [
711
+ "field",
712
+ "op",
713
+ "values"
714
+ ],
715
+ "properties": {
716
+ "field": {
717
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
718
+ "type": "string"
719
+ },
720
+ "op": {
721
+ "type": "string",
722
+ "enum": [
723
+ "in"
724
+ ]
725
+ },
726
+ "values": {
727
+ "description": "Array of values to filter by. Each value can be a string, number, boolean, or null.",
728
+ "type": [
729
+ "array"
730
+ ],
731
+ "items": {
732
+ "type": [
733
+ "string",
734
+ "number",
735
+ "boolean",
736
+ "null"
737
+ ]
738
+ }
739
+ }
740
+ }
741
+ },
742
+ {
743
+ "type": "object",
744
+ "required": [
745
+ "field",
746
+ "op",
747
+ "values"
748
+ ],
749
+ "properties": {
750
+ "field": {
751
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
752
+ "type": "string"
753
+ },
754
+ "op": {
755
+ "type": "string",
756
+ "enum": [
757
+ "not_in"
758
+ ]
759
+ },
760
+ "values": {
761
+ "description": "Array of values to filter by. Each value can be a string, number, boolean, or null.",
762
+ "type": [
763
+ "array"
764
+ ],
765
+ "items": {
766
+ "type": [
767
+ "string",
768
+ "number",
769
+ "boolean",
770
+ "null"
771
+ ]
772
+ }
773
+ }
774
+ }
775
+ },
776
+ {
777
+ "type": "object",
778
+ "required": [
779
+ "field",
780
+ "from",
781
+ "op",
782
+ "to"
783
+ ],
784
+ "properties": {
785
+ "field": {
786
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
787
+ "type": "string"
788
+ },
789
+ "from": {
790
+ "description": "Start of the date range. Can be a string (ISO date or relative like 'today', '7 days ago'), number (timestamp).",
791
+ "type": [
792
+ "string",
793
+ "number",
794
+ "boolean",
795
+ "null"
796
+ ]
797
+ },
798
+ "op": {
799
+ "type": "string",
800
+ "enum": [
801
+ "in_date_range"
802
+ ]
803
+ },
804
+ "to": {
805
+ "description": "End of the date range. Can be a string (ISO date or relative like 'today', '7 days ago'), number (timestamp).",
806
+ "type": [
807
+ "string",
808
+ "number",
809
+ "boolean",
810
+ "null"
811
+ ]
812
+ }
813
+ }
814
+ },
815
+ {
816
+ "type": "object",
817
+ "required": [
818
+ "field",
819
+ "from",
820
+ "op",
821
+ "to"
822
+ ],
823
+ "properties": {
824
+ "field": {
825
+ "description": "The measure/dimension to apply the filter on. Must by full name: <view_name>.<field_name>",
826
+ "type": "string"
827
+ },
828
+ "from": {
829
+ "description": "Start of the date range. Can be a string (ISO date or relative like 'today', '7 days ago'), number (timestamp).",
830
+ "type": [
831
+ "string",
832
+ "number",
833
+ "boolean",
834
+ "null"
835
+ ]
836
+ },
837
+ "op": {
838
+ "type": "string",
839
+ "enum": [
840
+ "not_in_date_range"
841
+ ]
842
+ },
843
+ "to": {
844
+ "description": "End of the date range. Can be a string (ISO date or relative like 'today', '7 days ago'), number (timestamp).",
845
+ "type": [
846
+ "string",
847
+ "number",
848
+ "boolean",
849
+ "null"
850
+ ]
851
+ }
852
+ }
853
+ }
854
+ ]
855
+ },
856
+ "SemanticFilterType": {
857
+ "description": "Enum representing different filter types with their appropriate value types",
858
+ "oneOf": [
859
+ {
860
+ "description": "Scalar comparison filter (eq, neq, gt, gte, lt, lte)",
861
+ "type": "object",
862
+ "required": [
863
+ "op",
864
+ "value"
865
+ ],
866
+ "properties": {
867
+ "op": {
868
+ "type": "string",
869
+ "enum": [
870
+ "eq"
871
+ ]
872
+ },
873
+ "value": {
874
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
875
+ "type": [
876
+ "string",
877
+ "number",
878
+ "boolean",
879
+ "null"
880
+ ]
881
+ }
882
+ }
883
+ },
884
+ {
885
+ "description": "Scalar comparison filter (eq, neq, gt, gte, lt, lte)",
886
+ "type": "object",
887
+ "required": [
888
+ "op",
889
+ "value"
890
+ ],
891
+ "properties": {
892
+ "op": {
893
+ "type": "string",
894
+ "enum": [
895
+ "neq"
896
+ ]
897
+ },
898
+ "value": {
899
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
900
+ "type": [
901
+ "string",
902
+ "number",
903
+ "boolean",
904
+ "null"
905
+ ]
906
+ }
907
+ }
908
+ },
909
+ {
910
+ "description": "Scalar comparison filter (eq, neq, gt, gte, lt, lte)",
911
+ "type": "object",
912
+ "required": [
913
+ "op",
914
+ "value"
915
+ ],
916
+ "properties": {
917
+ "op": {
918
+ "type": "string",
919
+ "enum": [
920
+ "gt"
921
+ ]
922
+ },
923
+ "value": {
924
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
925
+ "type": [
926
+ "string",
927
+ "number",
928
+ "boolean",
929
+ "null"
930
+ ]
931
+ }
932
+ }
933
+ },
934
+ {
935
+ "description": "Scalar comparison filter (eq, neq, gt, gte, lt, lte)",
936
+ "type": "object",
937
+ "required": [
938
+ "op",
939
+ "value"
940
+ ],
941
+ "properties": {
942
+ "op": {
943
+ "type": "string",
944
+ "enum": [
945
+ "gte"
946
+ ]
947
+ },
948
+ "value": {
949
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
950
+ "type": [
951
+ "string",
952
+ "number",
953
+ "boolean",
954
+ "null"
955
+ ]
956
+ }
957
+ }
958
+ },
959
+ {
960
+ "description": "Scalar comparison filter (eq, neq, gt, gte, lt, lte)",
961
+ "type": "object",
962
+ "required": [
963
+ "op",
964
+ "value"
965
+ ],
966
+ "properties": {
967
+ "op": {
968
+ "type": "string",
969
+ "enum": [
970
+ "lt"
971
+ ]
972
+ },
973
+ "value": {
974
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
975
+ "type": [
976
+ "string",
977
+ "number",
978
+ "boolean",
979
+ "null"
980
+ ]
981
+ }
982
+ }
983
+ },
984
+ {
985
+ "description": "Scalar comparison filter (eq, neq, gt, gte, lt, lte)",
986
+ "type": "object",
987
+ "required": [
988
+ "op",
989
+ "value"
990
+ ],
991
+ "properties": {
992
+ "op": {
993
+ "type": "string",
994
+ "enum": [
995
+ "lte"
996
+ ]
997
+ },
998
+ "value": {
999
+ "description": "The value to compare. Can be a string, number, boolean, or null.",
1000
+ "type": [
1001
+ "string",
1002
+ "number",
1003
+ "boolean",
1004
+ "null"
1005
+ ]
1006
+ }
1007
+ }
1008
+ },
1009
+ {
1010
+ "description": "Array-based filter (in, not_in)",
1011
+ "type": "object",
1012
+ "required": [
1013
+ "op",
1014
+ "values"
1015
+ ],
1016
+ "properties": {
1017
+ "op": {
1018
+ "type": "string",
1019
+ "enum": [
1020
+ "in"
1021
+ ]
1022
+ },
1023
+ "values": {
1024
+ "description": "Array of values to filter by. Each value can be a string, number, boolean, or null.",
1025
+ "type": [
1026
+ "array"
1027
+ ],
1028
+ "items": {
1029
+ "type": [
1030
+ "string",
1031
+ "number",
1032
+ "boolean",
1033
+ "null"
1034
+ ]
1035
+ }
1036
+ }
1037
+ }
1038
+ },
1039
+ {
1040
+ "description": "Array-based filter (in, not_in)",
1041
+ "type": "object",
1042
+ "required": [
1043
+ "op",
1044
+ "values"
1045
+ ],
1046
+ "properties": {
1047
+ "op": {
1048
+ "type": "string",
1049
+ "enum": [
1050
+ "not_in"
1051
+ ]
1052
+ },
1053
+ "values": {
1054
+ "description": "Array of values to filter by. Each value can be a string, number, boolean, or null.",
1055
+ "type": [
1056
+ "array"
1057
+ ],
1058
+ "items": {
1059
+ "type": [
1060
+ "string",
1061
+ "number",
1062
+ "boolean",
1063
+ "null"
1064
+ ]
1065
+ }
1066
+ }
1067
+ }
1068
+ },
1069
+ {
1070
+ "description": "Date range filter (in_date_range, not_in_date_range)",
1071
+ "type": "object",
1072
+ "required": [
1073
+ "from",
1074
+ "op",
1075
+ "to"
1076
+ ],
1077
+ "properties": {
1078
+ "from": {
1079
+ "description": "Start of the date range. Can be a string (ISO date or relative like 'today', '7 days ago'), number (timestamp).",
1080
+ "type": [
1081
+ "string",
1082
+ "number",
1083
+ "boolean",
1084
+ "null"
1085
+ ]
1086
+ },
1087
+ "op": {
1088
+ "type": "string",
1089
+ "enum": [
1090
+ "in_date_range"
1091
+ ]
1092
+ },
1093
+ "to": {
1094
+ "description": "End of the date range. Can be a string (ISO date or relative like 'today', '7 days ago'), number (timestamp).",
1095
+ "type": [
1096
+ "string",
1097
+ "number",
1098
+ "boolean",
1099
+ "null"
1100
+ ]
1101
+ }
1102
+ }
1103
+ },
1104
+ {
1105
+ "description": "Date range filter (in_date_range, not_in_date_range)",
1106
+ "type": "object",
1107
+ "required": [
1108
+ "from",
1109
+ "op",
1110
+ "to"
1111
+ ],
1112
+ "properties": {
1113
+ "from": {
1114
+ "description": "Start of the date range. Can be a string (ISO date or relative like 'today', '7 days ago'), number (timestamp).",
1115
+ "type": [
1116
+ "string",
1117
+ "number",
1118
+ "boolean",
1119
+ "null"
1120
+ ]
1121
+ },
1122
+ "op": {
1123
+ "type": "string",
1124
+ "enum": [
1125
+ "not_in_date_range"
1126
+ ]
1127
+ },
1128
+ "to": {
1129
+ "description": "End of the date range. Can be a string (ISO date or relative like 'today', '7 days ago'), number (timestamp).",
1130
+ "type": [
1131
+ "string",
1132
+ "number",
1133
+ "boolean",
1134
+ "null"
1135
+ ]
1136
+ }
1137
+ }
1138
+ }
1139
+ ]
1140
+ },
1141
+ "SemanticQueryOrder": {
1142
+ "type": "object",
1143
+ "required": [
1144
+ "direction",
1145
+ "field"
1146
+ ],
1147
+ "properties": {
1148
+ "direction": {
1149
+ "type": "string"
1150
+ },
1151
+ "field": {
1152
+ "type": "string"
1153
+ }
1154
+ }
1155
+ },
1156
+ "Task": {
1157
+ "type": "object",
1158
+ "oneOf": [
1159
+ {
1160
+ "type": "object",
1161
+ "required": [
1162
+ "agent_ref",
1163
+ "prompt",
1164
+ "type"
1165
+ ],
1166
+ "properties": {
1167
+ "agent_ref": {
1168
+ "type": "string"
1169
+ },
1170
+ "consistency_prompt": {
1171
+ "description": "Custom consistency evaluation prompt for this specific task Overrides automation-level consistency_prompt if specified",
1172
+ "type": [
1173
+ "string",
1174
+ "null"
1175
+ ]
1176
+ },
1177
+ "consistency_run": {
1178
+ "default": 1,
1179
+ "type": "integer",
1180
+ "format": "uint",
1181
+ "minimum": 0.0
1182
+ },
1183
+ "export": {
1184
+ "anyOf": [
1185
+ {
1186
+ "$ref": "#/definitions/TaskExport"
1187
+ },
1188
+ {
1189
+ "type": "null"
1190
+ }
1191
+ ]
1192
+ },
1193
+ "prompt": {
1194
+ "type": "string"
1195
+ },
1196
+ "retry": {
1197
+ "default": 1,
1198
+ "type": "integer",
1199
+ "format": "uint",
1200
+ "minimum": 0.0
1201
+ },
1202
+ "type": {
1203
+ "type": "string",
1204
+ "enum": [
1205
+ "agent"
1206
+ ]
1207
+ },
1208
+ "variables": {
1209
+ "type": [
1210
+ "object",
1211
+ "null"
1212
+ ],
1213
+ "additionalProperties": true
1214
+ }
1215
+ }
1216
+ },
1217
+ {
1218
+ "type": "object",
1219
+ "anyOf": [
1220
+ {
1221
+ "type": "object",
1222
+ "required": [
1223
+ "sql_file"
1224
+ ],
1225
+ "properties": {
1226
+ "sql_file": {
1227
+ "type": "string"
1228
+ }
1229
+ }
1230
+ },
1231
+ {
1232
+ "type": "object",
1233
+ "required": [
1234
+ "sql_query"
1235
+ ],
1236
+ "properties": {
1237
+ "sql_query": {
1238
+ "type": "string"
1239
+ }
1240
+ }
1241
+ }
1242
+ ],
1243
+ "required": [
1244
+ "database",
1245
+ "type"
1246
+ ],
1247
+ "properties": {
1248
+ "database": {
1249
+ "type": "string"
1250
+ },
1251
+ "dry_run_limit": {
1252
+ "type": [
1253
+ "integer",
1254
+ "null"
1255
+ ],
1256
+ "format": "uint64",
1257
+ "minimum": 0.0
1258
+ },
1259
+ "export": {
1260
+ "anyOf": [
1261
+ {
1262
+ "$ref": "#/definitions/TaskExport"
1263
+ },
1264
+ {
1265
+ "type": "null"
1266
+ }
1267
+ ]
1268
+ },
1269
+ "type": {
1270
+ "type": "string",
1271
+ "enum": [
1272
+ "execute_sql"
1273
+ ]
1274
+ },
1275
+ "variables": {
1276
+ "default": null,
1277
+ "type": [
1278
+ "object",
1279
+ "null"
1280
+ ],
1281
+ "additionalProperties": {
1282
+ "type": "string"
1283
+ }
1284
+ }
1285
+ }
1286
+ },
1287
+ {
1288
+ "type": "object",
1289
+ "required": [
1290
+ "type"
1291
+ ],
1292
+ "properties": {
1293
+ "dimensions": {
1294
+ "description": "List of dimensions to include in the query. Format: <view_name>.<dimension_name>",
1295
+ "type": "array",
1296
+ "items": {
1297
+ "type": "string"
1298
+ }
1299
+ },
1300
+ "export": {
1301
+ "anyOf": [
1302
+ {
1303
+ "$ref": "#/definitions/TaskExport"
1304
+ },
1305
+ {
1306
+ "type": "null"
1307
+ }
1308
+ ]
1309
+ },
1310
+ "filters": {
1311
+ "type": "array",
1312
+ "items": {
1313
+ "$ref": "#/definitions/SemanticFilter"
1314
+ }
1315
+ },
1316
+ "limit": {
1317
+ "type": [
1318
+ "integer",
1319
+ "null"
1320
+ ],
1321
+ "format": "uint64",
1322
+ "minimum": 0.0
1323
+ },
1324
+ "measures": {
1325
+ "description": "List of measures to include in the query. Format: <view_name>.<measure_name>",
1326
+ "type": "array",
1327
+ "items": {
1328
+ "type": "string"
1329
+ }
1330
+ },
1331
+ "offset": {
1332
+ "type": [
1333
+ "integer",
1334
+ "null"
1335
+ ],
1336
+ "format": "uint64",
1337
+ "minimum": 0.0
1338
+ },
1339
+ "orders": {
1340
+ "type": "array",
1341
+ "items": {
1342
+ "$ref": "#/definitions/SemanticQueryOrder"
1343
+ }
1344
+ },
1345
+ "time_dimensions": {
1346
+ "description": "List of time dimensions with granularity and date range. Can only use with dimensions of type time or datetime. Format: <view_name>.<dimension_name>",
1347
+ "type": "array",
1348
+ "items": {
1349
+ "$ref": "#/definitions/TimeDimension"
1350
+ }
1351
+ },
1352
+ "topic": {
1353
+ "default": null,
1354
+ "type": [
1355
+ "string",
1356
+ "null"
1357
+ ]
1358
+ },
1359
+ "type": {
1360
+ "type": "string",
1361
+ "enum": [
1362
+ "semantic_query"
1363
+ ]
1364
+ },
1365
+ "variables": {
1366
+ "description": "Variables to resolve in semantic model expressions. Use {{variables.variable_name}} syntax in semantic definitions.",
1367
+ "type": [
1368
+ "object",
1369
+ "null"
1370
+ ],
1371
+ "additionalProperties": true
1372
+ }
1373
+ }
1374
+ },
1375
+ {
1376
+ "type": "object",
1377
+ "required": [
1378
+ "fields",
1379
+ "integration",
1380
+ "topic",
1381
+ "type"
1382
+ ],
1383
+ "properties": {
1384
+ "export": {
1385
+ "anyOf": [
1386
+ {
1387
+ "$ref": "#/definitions/TaskExport"
1388
+ },
1389
+ {
1390
+ "type": "null"
1391
+ }
1392
+ ]
1393
+ },
1394
+ "fields": {
1395
+ "description": "Fields to select. Field name must be full name format {view}.{field_name}. No aggregation or any other syntax.",
1396
+ "type": "array",
1397
+ "items": {
1398
+ "type": "string"
1399
+ }
1400
+ },
1401
+ "integration": {
1402
+ "type": "string"
1403
+ },
1404
+ "limit": {
1405
+ "description": "Maximum number of rows to return.",
1406
+ "type": [
1407
+ "integer",
1408
+ "null"
1409
+ ],
1410
+ "format": "uint64",
1411
+ "minimum": 0.0
1412
+ },
1413
+ "sorts": {
1414
+ "description": "Fields to sort by with direction (asc/desc).",
1415
+ "type": [
1416
+ "object",
1417
+ "null"
1418
+ ],
1419
+ "additionalProperties": {
1420
+ "$ref": "#/definitions/OrderType"
1421
+ }
1422
+ },
1423
+ "topic": {
1424
+ "type": "string"
1425
+ },
1426
+ "type": {
1427
+ "type": "string",
1428
+ "enum": [
1429
+ "omni_query"
1430
+ ]
1431
+ }
1432
+ }
1433
+ },
1434
+ {
1435
+ "description": "Task configuration for executing a Looker query within an automation.",
1436
+ "type": "object",
1437
+ "required": [
1438
+ "explore",
1439
+ "fields",
1440
+ "integration",
1441
+ "model",
1442
+ "type"
1443
+ ],
1444
+ "properties": {
1445
+ "explore": {
1446
+ "description": "The explore name within the model",
1447
+ "type": "string"
1448
+ },
1449
+ "export": {
1450
+ "description": "Optional export configuration for query results",
1451
+ "anyOf": [
1452
+ {
1453
+ "$ref": "#/definitions/TaskExport"
1454
+ },
1455
+ {
1456
+ "type": "null"
1457
+ }
1458
+ ]
1459
+ },
1460
+ "fields": {
1461
+ "description": "Fields to select. Field name must be full name format {view}.{field_name}.",
1462
+ "type": "array",
1463
+ "items": {
1464
+ "type": "string"
1465
+ }
1466
+ },
1467
+ "filter_expression": {
1468
+ "description": "Looker filter expression for complex conditions.",
1469
+ "type": [
1470
+ "string",
1471
+ "null"
1472
+ ]
1473
+ },
1474
+ "filters": {
1475
+ "description": "Filter conditions as field name to Looker filter expression mappings.",
1476
+ "type": [
1477
+ "object",
1478
+ "null"
1479
+ ],
1480
+ "additionalProperties": {
1481
+ "type": "string"
1482
+ }
1483
+ },
1484
+ "integration": {
1485
+ "description": "Name of the Looker integration to use",
1486
+ "type": "string"
1487
+ },
1488
+ "limit": {
1489
+ "description": "Maximum number of rows to return.",
1490
+ "type": [
1491
+ "integer",
1492
+ "null"
1493
+ ],
1494
+ "format": "int64"
1495
+ },
1496
+ "model": {
1497
+ "description": "The LookML model name",
1498
+ "type": "string"
1499
+ },
1500
+ "sorts": {
1501
+ "description": "Fields to sort by using Looker syntax: 'view.field asc' or 'view.field desc'.",
1502
+ "type": [
1503
+ "array",
1504
+ "null"
1505
+ ],
1506
+ "items": {
1507
+ "$ref": "#/definitions/LookerSortField"
1508
+ }
1509
+ },
1510
+ "type": {
1511
+ "type": "string",
1512
+ "enum": [
1513
+ "looker_query"
1514
+ ]
1515
+ }
1516
+ }
1517
+ },
1518
+ {
1519
+ "type": "object",
1520
+ "required": [
1521
+ "tasks",
1522
+ "type",
1523
+ "values"
1524
+ ],
1525
+ "properties": {
1526
+ "concurrency": {
1527
+ "default": 1,
1528
+ "type": "integer",
1529
+ "format": "uint",
1530
+ "minimum": 0.0
1531
+ },
1532
+ "tasks": {
1533
+ "type": "array",
1534
+ "items": {
1535
+ "$ref": "#/definitions/Task"
1536
+ }
1537
+ },
1538
+ "type": {
1539
+ "type": "string",
1540
+ "enum": [
1541
+ "loop_sequential"
1542
+ ]
1543
+ },
1544
+ "values": {
1545
+ "$ref": "#/definitions/LoopValues"
1546
+ }
1547
+ }
1548
+ },
1549
+ {
1550
+ "type": "object",
1551
+ "required": [
1552
+ "template",
1553
+ "type"
1554
+ ],
1555
+ "properties": {
1556
+ "export": {
1557
+ "anyOf": [
1558
+ {
1559
+ "$ref": "#/definitions/TaskExport"
1560
+ },
1561
+ {
1562
+ "type": "null"
1563
+ }
1564
+ ]
1565
+ },
1566
+ "template": {
1567
+ "type": "string"
1568
+ },
1569
+ "type": {
1570
+ "type": "string",
1571
+ "enum": [
1572
+ "formatter"
1573
+ ]
1574
+ }
1575
+ }
1576
+ },
1577
+ {
1578
+ "type": "object",
1579
+ "required": [
1580
+ "src",
1581
+ "type"
1582
+ ],
1583
+ "properties": {
1584
+ "export": {
1585
+ "anyOf": [
1586
+ {
1587
+ "$ref": "#/definitions/TaskExport"
1588
+ },
1589
+ {
1590
+ "type": "null"
1591
+ }
1592
+ ]
1593
+ },
1594
+ "src": {
1595
+ "type": "string"
1596
+ },
1597
+ "type": {
1598
+ "type": "string",
1599
+ "enum": [
1600
+ "workflow"
1601
+ ]
1602
+ },
1603
+ "variables": {
1604
+ "type": [
1605
+ "object",
1606
+ "null"
1607
+ ],
1608
+ "additionalProperties": true
1609
+ }
1610
+ }
1611
+ },
1612
+ {
1613
+ "type": "object",
1614
+ "required": [
1615
+ "conditions",
1616
+ "type"
1617
+ ],
1618
+ "properties": {
1619
+ "conditions": {
1620
+ "type": "array",
1621
+ "items": {
1622
+ "$ref": "#/definitions/Condition"
1623
+ }
1624
+ },
1625
+ "else": {
1626
+ "default": null,
1627
+ "type": [
1628
+ "array",
1629
+ "null"
1630
+ ],
1631
+ "items": {
1632
+ "$ref": "#/definitions/Task"
1633
+ }
1634
+ },
1635
+ "type": {
1636
+ "type": "string",
1637
+ "enum": [
1638
+ "conditional"
1639
+ ]
1640
+ }
1641
+ }
1642
+ },
1643
+ {
1644
+ "description": "`type: http_request` — make an outbound HTTP request from a workflow.\n\nThe reusable primitive behind the QuickBooks JE-posting automation (and the stop-gap for Oxy Functions' `ctx.fetch`). Templated fields render against the prior-step render context; `{{ secrets.NAME }}` resolves declared `secrets`. Egress is constrained (private/loopback/link-local hosts are always denied; `allow_hosts`, when set, is an additional allowlist).",
1645
+ "type": "object",
1646
+ "required": [
1647
+ "type",
1648
+ "url"
1649
+ ],
1650
+ "properties": {
1651
+ "allow_hosts": {
1652
+ "description": "Allowed target hostnames (in addition to the always-on private-IP deny). Empty means \"any public host\"; set it to lock a task to specific APIs.",
1653
+ "default": [],
1654
+ "type": "array",
1655
+ "items": {
1656
+ "type": "string"
1657
+ }
1658
+ },
1659
+ "body": {
1660
+ "description": "Raw request body (Jinja-templated). Mutually exclusive with `form`.",
1661
+ "default": null,
1662
+ "type": [
1663
+ "string",
1664
+ "null"
1665
+ ]
1666
+ },
1667
+ "expected_status": {
1668
+ "description": "Accepted HTTP status codes. Empty → any 2xx is accepted; anything else fails the task.",
1669
+ "default": [],
1670
+ "type": "array",
1671
+ "items": {
1672
+ "type": "integer",
1673
+ "format": "uint16",
1674
+ "minimum": 0.0
1675
+ }
1676
+ },
1677
+ "form": {
1678
+ "description": "Form fields serialized as `application/x-www-form-urlencoded` (values templated).",
1679
+ "default": null,
1680
+ "type": [
1681
+ "object",
1682
+ "null"
1683
+ ],
1684
+ "additionalProperties": {
1685
+ "type": "string"
1686
+ }
1687
+ },
1688
+ "headers": {
1689
+ "description": "Request headers; values are Jinja-templated and may reference `{{ secrets.X }}`.",
1690
+ "default": {},
1691
+ "type": "object",
1692
+ "additionalProperties": {
1693
+ "type": "string"
1694
+ }
1695
+ },
1696
+ "method": {
1697
+ "description": "HTTP method (GET/POST/PUT/PATCH/DELETE). Defaults to POST.",
1698
+ "default": "POST",
1699
+ "type": "string"
1700
+ },
1701
+ "persist_to_secret": {
1702
+ "description": "Optionally write a field of the JSON response back into a project secret.",
1703
+ "default": null,
1704
+ "anyOf": [
1705
+ {
1706
+ "$ref": "#/definitions/PersistToSecret"
1707
+ },
1708
+ {
1709
+ "type": "null"
1710
+ }
1711
+ ]
1712
+ },
1713
+ "secrets": {
1714
+ "description": "Project secret names to resolve into the `{{ secrets.NAME }}` template scope.",
1715
+ "default": [],
1716
+ "type": "array",
1717
+ "items": {
1718
+ "type": "string"
1719
+ }
1720
+ },
1721
+ "timeout_secs": {
1722
+ "description": "Request timeout in seconds (1–120). Defaults to 30.",
1723
+ "default": 30,
1724
+ "type": "integer",
1725
+ "format": "uint64",
1726
+ "minimum": 0.0
1727
+ },
1728
+ "type": {
1729
+ "type": "string",
1730
+ "enum": [
1731
+ "http_request"
1732
+ ]
1733
+ },
1734
+ "url": {
1735
+ "description": "Request URL (Jinja-templated).",
1736
+ "type": "string"
1737
+ }
1738
+ }
1739
+ },
1740
+ {
1741
+ "description": "Run an airway ELT pipeline as an automation step.\n\nUnlike the other I/O task types this is **not** executed by `step_executor` — it is delegated as a `TaskSpec::Airway`, reusing the existing airway run path (secret resolution, Airhouse credential minting, backfill windowing, run-scoped state). See `StepKind::Airway`.\n\nA step completes only once the pipeline's end-of-load fold has committed, so a following `execute_sql` step reads a queryable table rather than a half-folded one.",
1742
+ "type": "object",
1743
+ "required": [
1744
+ "pipeline",
1745
+ "type"
1746
+ ],
1747
+ "properties": {
1748
+ "pipeline": {
1749
+ "description": "Workspace-relative path to the `.airway.yml` pipeline spec.",
1750
+ "type": "string"
1751
+ },
1752
+ "resources": {
1753
+ "description": "Explicit subset of the spec's resources (tables) to run. Omitted or empty runs the whole pipeline.",
1754
+ "default": null,
1755
+ "type": [
1756
+ "array",
1757
+ "null"
1758
+ ],
1759
+ "items": {
1760
+ "type": "string"
1761
+ }
1762
+ },
1763
+ "type": {
1764
+ "type": "string",
1765
+ "enum": [
1766
+ "airway"
1767
+ ]
1768
+ }
1769
+ }
1770
+ },
1771
+ {
1772
+ "type": "object",
1773
+ "required": [
1774
+ "type"
1775
+ ],
1776
+ "properties": {
1777
+ "type": {
1778
+ "type": "string",
1779
+ "enum": [
1780
+ "Unknown"
1781
+ ]
1782
+ }
1783
+ }
1784
+ }
1785
+ ],
1786
+ "required": [
1787
+ "name"
1788
+ ],
1789
+ "properties": {
1790
+ "cache": {
1791
+ "anyOf": [
1792
+ {
1793
+ "$ref": "#/definitions/TaskCache"
1794
+ },
1795
+ {
1796
+ "type": "null"
1797
+ }
1798
+ ]
1799
+ },
1800
+ "mode": {
1801
+ "description": "Execution mode when this task is used inside a data app. Defaults to `client`.",
1802
+ "default": "client",
1803
+ "allOf": [
1804
+ {
1805
+ "$ref": "#/definitions/AppTaskMode"
1806
+ }
1807
+ ]
1808
+ },
1809
+ "name": {
1810
+ "description": "Unique name for the task within the workflow. Format: alphanumeric and underscores only, starting with a letter.",
1811
+ "type": "string"
1812
+ }
1813
+ }
1814
+ },
1815
+ "TaskCache": {
1816
+ "type": "object",
1817
+ "required": [
1818
+ "path"
1819
+ ],
1820
+ "properties": {
1821
+ "enabled": {
1822
+ "default": false,
1823
+ "type": "boolean"
1824
+ },
1825
+ "path": {
1826
+ "type": "string"
1827
+ }
1828
+ }
1829
+ },
1830
+ "TaskExport": {
1831
+ "type": "object",
1832
+ "required": [
1833
+ "format",
1834
+ "path"
1835
+ ],
1836
+ "properties": {
1837
+ "format": {
1838
+ "$ref": "#/definitions/ExportFormat"
1839
+ },
1840
+ "path": {
1841
+ "type": "string"
1842
+ }
1843
+ }
1844
+ },
1845
+ "TimeDimension": {
1846
+ "description": "Time dimension for temporal queries with granularity and date range",
1847
+ "type": "object",
1848
+ "required": [
1849
+ "dimension"
1850
+ ],
1851
+ "properties": {
1852
+ "dimension": {
1853
+ "description": "Dimension name in format: <view_name>.<dimension_name>",
1854
+ "type": "string"
1855
+ },
1856
+ "granularity": {
1857
+ "description": "Time granularity for grouping (year, month, day, etc.)",
1858
+ "anyOf": [
1859
+ {
1860
+ "$ref": "#/definitions/TimeGranularity"
1861
+ },
1862
+ {
1863
+ "type": "null"
1864
+ }
1865
+ ]
1866
+ }
1867
+ }
1868
+ },
1869
+ "TimeGranularity": {
1870
+ "description": "Time granularity options for time dimension queries",
1871
+ "type": "string",
1872
+ "enum": [
1873
+ "year",
1874
+ "quarter",
1875
+ "month",
1876
+ "week",
1877
+ "day",
1878
+ "hour",
1879
+ "minute",
1880
+ "second"
1881
+ ]
1882
+ }
1883
+ }
1884
+ }