@metabase/cli 0.1.17 → 0.2.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 (224) hide show
  1. package/README.md +61 -35
  2. package/dist/{add-collection-C-t9SQBk.mjs → add-collection-BTSGp4f9.mjs} +4 -5
  3. package/dist/add-collection-DlAwt2Z3.mjs +9 -0
  4. package/dist/append-DY1-O789.mjs +42 -0
  5. package/dist/{archive-wNXwIiF0.mjs → archive-BOEEMrYL.mjs} +6 -8
  6. package/dist/{archive-CaoUUTIb.mjs → archive-CJ9rElKn.mjs} +6 -8
  7. package/dist/{archive-DS-KEB4a.mjs → archive-CWtUzlHO.mjs} +5 -7
  8. package/dist/{archive-LG8u7ec5.mjs → archive-DCPw3df6.mjs} +5 -7
  9. package/dist/{archive-D1FX-sbU.mjs → archive-DOa1u1aJ.mjs} +5 -7
  10. package/dist/{archive-C7dnyzVY.mjs → archive-pHsa4dL0.mjs} +8 -9
  11. package/dist/{archive-qSOcACQo.mjs → archive-w6TX-zEk.mjs} +7 -8
  12. package/dist/auth-BrQtY0pO.mjs +22 -0
  13. package/dist/{body-IcJ5kFtk.mjs → body-C1_AaTS4.mjs} +3 -3
  14. package/dist/{branches-BlNCTmFB.mjs → branches-BsBzaGIf.mjs} +5 -7
  15. package/dist/{cancel-BnveTPNw.mjs → cancel-BNM0yyx-.mjs} +4 -6
  16. package/dist/{cancel-task-CSVI8Zgl.mjs → cancel-task-Bggzn4JL.mjs} +5 -7
  17. package/dist/capabilities-DrDJo_ng.mjs +684 -0
  18. package/dist/{card-DEmcRlNO.mjs → card-B8G5jQQT.mjs} +24 -18
  19. package/dist/card-DHCcmpgr.mjs +26 -0
  20. package/dist/{cards-CMgGA8OZ.mjs → cards-D0hvA13L.mjs} +7 -8
  21. package/dist/cli.mjs +175 -29
  22. package/dist/{collection-DrLpA1SO.mjs → collection-CFoLPrY5.mjs} +1 -1
  23. package/dist/collection-D0O9gp3S.mjs +23 -0
  24. package/dist/{collection-namespace-CsaxEqOb.mjs → collection-namespace-DqPNrCdQ.mjs} +2 -2
  25. package/dist/{create-I5Cv-MBa.mjs → create-05rX4oL-.mjs} +11 -12
  26. package/dist/{create-B6LQutd0.mjs → create-BR7x66KW.mjs} +12 -13
  27. package/dist/{create-B79M8YpX.mjs → create-C17Fh1_X.mjs} +9 -10
  28. package/dist/{create-FZOrCw5k.mjs → create-C8ndg3g4.mjs} +28 -21
  29. package/dist/{create-C7u3umLj.mjs → create-CZ9KFnbi.mjs} +8 -9
  30. package/dist/{create-B1xfaZJB.mjs → create-Cii_utzV.mjs} +5 -7
  31. package/dist/{create-SHKlj0z3.mjs → create-Cyv7vHV_.mjs} +8 -9
  32. package/dist/{create-Bg_uMu0p.mjs → create-DKuixGJ2.mjs} +8 -9
  33. package/dist/{create-AeWNv0v-.mjs → create-E6L3WMqV.mjs} +8 -9
  34. package/dist/{create-LHqwcVbS.mjs → create-a3s1S2Dw.mjs} +11 -12
  35. package/dist/{create-branch-CGyT99Ny.mjs → create-branch-Dxn6UnV_.mjs} +5 -7
  36. package/dist/{create-BpkWlgoR.mjs → create-oLb0E-ZP.mjs} +17 -14
  37. package/dist/csv-T6_vlLJS.mjs +58 -0
  38. package/dist/{current-task-C-0hw2Ae.mjs → current-task-DxWbw-bU.mjs} +5 -7
  39. package/dist/{dashboard-DOplbKyQ.mjs → dashboard-B-MTpfeS.mjs} +35 -15
  40. package/dist/dashboard-BpSPoeAn.mjs +35 -0
  41. package/dist/{database-D9fftP-i.mjs → database-CIbVSfua.mjs} +2 -2
  42. package/dist/db-DBRijnh4.mjs +27 -0
  43. package/dist/{delete-tCVrYjKD.mjs → delete--P1xFX37.mjs} +6 -8
  44. package/dist/{delete-Do3nn9sl.mjs → delete-BBOIUl0D.mjs} +6 -8
  45. package/dist/{delete--NYYN6wv.mjs → delete-Ce2EBQYA.mjs} +6 -8
  46. package/dist/{delete-runtime-B0ha5QR4.mjs → delete-runtime-B-8I9V1g.mjs} +2 -3
  47. package/dist/{delete-table-CWSGPw0i.mjs → delete-table-Bj32NsXn.mjs} +6 -8
  48. package/dist/{dependencies-CyFocD8I.mjs → dependencies-ixzjVjUz.mjs} +5 -7
  49. package/dist/{dirty-BXM0YJ_a.mjs → dirty-CH70h5m5.mjs} +5 -7
  50. package/dist/{document-1W7NRaO_.mjs → document-CL4ML5FN.mjs} +20 -4
  51. package/dist/document-dZpuFu3I.mjs +22 -0
  52. package/dist/{eid-p-zn_1RJ.mjs → eid-XjkBbyb_.mjs} +10 -11
  53. package/dist/embedding-CKdw8q7p.mjs +11 -0
  54. package/dist/{export-B_8wghyo.mjs → export-CChMg-mL.mjs} +7 -9
  55. package/dist/field-B1heFeCz.mjs +21 -0
  56. package/dist/{field-CMY_LWUe.mjs → field-DsXTeqBy.mjs} +6 -4
  57. package/dist/{fields-BsufL9kv.mjs → fields-C7h2QwUp.mjs} +6 -8
  58. package/dist/{get-Cl5Ak73C.mjs → get-AvGH_oph.mjs} +8 -9
  59. package/dist/{get-DurjkUKJ.mjs → get-B6ZJCJ8H.mjs} +5 -7
  60. package/dist/{get-68P-L4ja.mjs → get-BWHJDa0B.mjs} +5 -7
  61. package/dist/{get-B67pe00Z.mjs → get-BsyccuCH.mjs} +5 -7
  62. package/dist/{get-C7mq17-2.mjs → get-C98IFgFi.mjs} +5 -7
  63. package/dist/{get-BTKeO4vE.mjs → get-Cj90oyxG.mjs} +5 -7
  64. package/dist/{get-BJoZkATD.mjs → get-D9r2znrn.mjs} +5 -7
  65. package/dist/{get-D3k2JUsa.mjs → get-DRZENkCj.mjs} +5 -7
  66. package/dist/{get-4lufgahL.mjs → get-DWWmpQ87.mjs} +5 -7
  67. package/dist/{get-CPw0ROO4.mjs → get-Dg1J0wxb.mjs} +5 -7
  68. package/dist/{get-B45uYMAs.mjs → get-DrWYvefc.mjs} +7 -8
  69. package/dist/{get-DTqBuIf3.mjs → get-KVN9ANVh.mjs} +4 -6
  70. package/dist/get-RlP_xiUd.mjs +67 -0
  71. package/dist/{get-Df_3LCVC.mjs → get-cyR67Lmq.mjs} +5 -7
  72. package/dist/{get-DeLnNVQE.mjs → get-kqY2lwhO.mjs} +16 -9
  73. package/dist/{get-run-Dq4qfGfD.mjs → get-run-C4C_QQqO.mjs} +5 -7
  74. package/dist/git-sync-JHa7bIyY.mjs +31 -0
  75. package/dist/{group-BNE_RiH5.mjs → group-CILtQqCL.mjs} +2 -1
  76. package/dist/{has-remote-changes-E-4N_O_t.mjs → has-remote-changes-dLUGr0MD.mjs} +5 -7
  77. package/dist/{import-Dg0j3HCP.mjs → import-Byull6jF.mjs} +7 -9
  78. package/dist/{input-7Sj85_K7.mjs → input-m9ctfLxZ.mjs} +6 -3
  79. package/dist/is-dirty-Bb2dfEYs.mjs +8 -0
  80. package/dist/{is-dirty-DWw1yBeR.mjs → is-dirty-CU3ovgdG.mjs} +3 -4
  81. package/dist/{items-CQtt9X4M.mjs → items-CEGDYWuF.mjs} +7 -9
  82. package/dist/{key-bltP32Pm.mjs → key-Ge4VwWvS.mjs} +1 -1
  83. package/dist/{library-B5AvpACG.mjs → library-DHWWa4Tt.mjs} +6 -6
  84. package/dist/{list-BFVuPodI.mjs → list-3z1ZChTG.mjs} +4 -6
  85. package/dist/{list-D3TSAqwl.mjs → list-B9TyELob.mjs} +4 -6
  86. package/dist/{list-BAOTQHst.mjs → list-BFm4iEBt.mjs} +4 -6
  87. package/dist/{list-BKUvhAs4.mjs → list-BliCJAjt.mjs} +4 -6
  88. package/dist/{list-BgUWqZa2.mjs → list-Bpv06V24.mjs} +6 -8
  89. package/dist/{list-DG0FIhTK.mjs → list-Br48kL09.mjs} +4 -6
  90. package/dist/{list-BHAWYZ1z.mjs → list-BtcpNl4-.mjs} +4 -6
  91. package/dist/{list-B1uVWy6A.mjs → list-BuyRG3GB.mjs} +7 -8
  92. package/dist/{list-CvhVYOVl.mjs → list-CMb03cv3.mjs} +5 -7
  93. package/dist/{list-CfqpDTna.mjs → list-CmCJwaGT.mjs} +4 -6
  94. package/dist/{list-C4bALfCs.mjs → list-Cur_72xZ.mjs} +5 -7
  95. package/dist/{list-BF-W4jOZ.mjs → list-D9FY30xH.mjs} +8 -9
  96. package/dist/{list-D5Gdz8hi.mjs → list-DEkPxVZu.mjs} +4 -6
  97. package/dist/{list-C9O2RY5u.mjs → list-O2w5xd1q.mjs} +4 -6
  98. package/dist/{list-KxQNqp4T.mjs → list-th_Ym6Cv.mjs} +6 -8
  99. package/dist/{login-Bt6j6yBM.mjs → login-hKlYsAa1.mjs} +8 -10
  100. package/dist/{logout-ANkL02p0.mjs → logout-DO8GVC6b.mjs} +4 -6
  101. package/dist/measure-R3T20wnB.mjs +25 -0
  102. package/dist/{measure-DoJvtCaA.mjs → measure-S9WszHre.mjs} +5 -4
  103. package/dist/{parameter-values-D4J8Ctu0.mjs → parameter-values-BJb2GuLz.mjs} +7 -9
  104. package/dist/{parse-enum-BL9i_brN.mjs → parse-enum-Cfne2suT.mjs} +1 -1
  105. package/dist/{parse-id-D4LeTUsP.mjs → parse-id-DfY0Lugw.mjs} +1 -1
  106. package/dist/{parse-ref-CB_KvF9h.mjs → parse-ref-C_MsXYI6.mjs} +1 -1
  107. package/dist/{path-5nQgdvrs.mjs → path-DzhQVCH8.mjs} +4 -6
  108. package/dist/{poll-BpAJpvb-.mjs → poll-D1Yg78c3.mjs} +2 -2
  109. package/dist/{poll-task-TilgciQn.mjs → poll-task-DLUZaglY.mjs} +2 -2
  110. package/dist/{preflight-OfHU3Toi.mjs → preflight-Cy2jUSca.mjs} +4 -5
  111. package/dist/{process-j8UHMHc2.mjs → process-D5HN1wpT.mjs} +1 -1
  112. package/dist/{prompt-C85xd9HR.mjs → prompt-ZG9Drin_.mjs} +1 -1
  113. package/dist/{publish-DKiqyDwo.mjs → publish-3hmHoaX-.mjs} +7 -9
  114. package/dist/{query-CQ3xXa9P.mjs → query-DTASj9Zu.mjs} +9 -10
  115. package/dist/{query-BWJ5h1g3.mjs → query-DkZViD_3.mjs} +15 -15
  116. package/dist/{query-result-D6mfoVfQ.mjs → query-result-CbTFdlSf.mjs} +1 -1
  117. package/dist/{remove-collection-CO-aMzTO.mjs → remove-collection-D3wH9H6R.mjs} +7 -9
  118. package/dist/replace-CFzqkZXs.mjs +42 -0
  119. package/dist/requests-KBiY9UYy.mjs +96 -0
  120. package/dist/{rescan-values-DpL6LGAK.mjs → rescan-values-B1WycObS.mjs} +7 -9
  121. package/dist/{resolve-Dj2MTBkn.mjs → resolve-Ct084wx3.mjs} +1 -1
  122. package/dist/{run-DUcdaZs3.mjs → run-B8qEEdC8.mjs} +4 -6
  123. package/dist/{run-QYJ-mAaG.mjs → run-cw0qTEQ7.mjs} +7 -9
  124. package/dist/{runs-DgasTnGd.mjs → runs-BOA4kK_X.mjs} +6 -8
  125. package/dist/{runtime-BJtuxWM8.mjs → runtime-B-c-Fc2i.mjs} +3 -4
  126. package/dist/{schema-tables-ooYjimrV.mjs → schema-tables-DRYzSVcW.mjs} +6 -8
  127. package/dist/{schemas-HjFPzsd-.mjs → schemas-BiMjD25L.mjs} +4 -6
  128. package/dist/{search-vaT5EwhG.mjs → search-DjKxRXO5.mjs} +4 -6
  129. package/dist/{segment-TXktTCfU.mjs → segment-BPb1H6DW.mjs} +6 -5
  130. package/dist/segment-CZkk0g79.mjs +25 -0
  131. package/dist/{selectors-DlmZpo2L.mjs → selectors-B7MJUn3I.mjs} +3 -3
  132. package/dist/{set-active-oZOUe9V7.mjs → set-active-CF868qdW.mjs} +4 -6
  133. package/dist/{set-CLHJauzG.mjs → set-kyoORFG3.mjs} +10 -10
  134. package/dist/setting-BZgjURQ_.mjs +20 -0
  135. package/dist/{setup-D1de5Sbc.mjs → setup-D9joJYPb.mjs} +11 -12
  136. package/dist/{skills-B6gfH0iR.mjs → skills-BqI05u72.mjs} +1 -1
  137. package/dist/{skills-NhgVypJ7.mjs → skills-D8NrJxjp.mjs} +3 -3
  138. package/dist/{snippet-CtA2Pkoa.mjs → snippet-DWiXNy4T.mjs} +7 -4
  139. package/dist/snippet-y_FzKxaQ.mjs +22 -0
  140. package/dist/{stash-DoRwelwY.mjs → stash-BVMerTaF.mjs} +7 -9
  141. package/dist/{status-CmRgHTrV.mjs → status-C-0jFjFn.mjs} +4 -6
  142. package/dist/{status-BpMOlfsA.mjs → status-x8bDOa1i.mjs} +6 -8
  143. package/dist/{summary-BEu7pmpq.mjs → summary-B-R9SdMF.mjs} +5 -7
  144. package/dist/{sync-schema-DTUXubMg.mjs → sync-schema-wne2KXIW.mjs} +9 -11
  145. package/dist/{table-DE3i82T_.mjs → table-C3RIKiYM.mjs} +16 -4
  146. package/dist/table-CS2-2INi.mjs +21 -0
  147. package/dist/transform-6hqM1DXA.mjs +31 -0
  148. package/dist/{transform-DEF38FWe.mjs → transform-JQel7e5H.mjs} +31 -5
  149. package/dist/transform-job-DuERhLaj.mjs +25 -0
  150. package/dist/transform-tag-DaNKreDj.mjs +21 -0
  151. package/dist/{transforms-CWvMpLc9.mjs → transforms-DB2WNP2R.mjs} +5 -7
  152. package/dist/{tree-D18vYSe4.mjs → tree-BIOphGVs.mjs} +4 -6
  153. package/dist/{unpublish-CJbL4ZsC.mjs → unpublish-BWM36ZTg.mjs} +5 -7
  154. package/dist/{update-mr9todHq.mjs → update-6umfSz5t.mjs} +9 -10
  155. package/dist/{update-BjjZIe2W.mjs → update-7Ts7KrB8.mjs} +9 -10
  156. package/dist/{update-Doia9MP_.mjs → update-BCbv880u.mjs} +12 -13
  157. package/dist/{update-CSxwZ2us.mjs → update-BchtHlbH.mjs} +10 -11
  158. package/dist/{update-BvsvyBw9.mjs → update-BiUeEGU-.mjs} +12 -13
  159. package/dist/{update-DhOfrW1j.mjs → update-BlzcZwRQ.mjs} +18 -15
  160. package/dist/{update-Bos8nnv0.mjs → update-CTZg2Lia.mjs} +13 -14
  161. package/dist/{update-DV7IY7IQ.mjs → update-DJDuIhYG.mjs} +9 -10
  162. package/dist/{update-Dxa_6H2A.mjs → update-HxYcvpSq.mjs} +15 -15
  163. package/dist/{update-Ck0Kxv8u.mjs → update-Sz0QRGWB.mjs} +9 -10
  164. package/dist/{update-dashcard-CZUWZhal.mjs → update-dashcard-CfDpy7Lz.mjs} +11 -11
  165. package/dist/{update-7DacwIvi.mjs → update-zfLbmC-H.mjs} +9 -10
  166. package/dist/{upgrade-CBW8V9qZ.mjs → upgrade-BWl0VjMK.mjs} +5 -7
  167. package/dist/upload-CPzOhGeX.mjs +16 -0
  168. package/dist/{uuid-D6JVJ-R1.mjs → uuid-D_YeqDui.mjs} +3 -5
  169. package/dist/{validate-BqNW4Sk1.mjs → validate-clAWO3X-.mjs} +1 -2
  170. package/dist/{validate-query-CcZVKYPV.mjs → validate-query-CsK2_2_u.mjs} +2 -3
  171. package/dist/{values-DBvuGnnA.mjs → values-DSk8ZJ3B.mjs} +5 -7
  172. package/dist/{verify-LIShMNZ2.mjs → verify-DkQdLjf3.mjs} +2 -2
  173. package/dist/{wait-DUHze3_B.mjs → wait-DvSsMjea.mjs} +6 -8
  174. package/dist/{wait-flags-Ybpt98PK.mjs → wait-flags-dXGThljd.mjs} +2 -2
  175. package/package.json +1 -1
  176. package/skill-data/core/SKILL.md +31 -22
  177. package/skill-data/dashboard/SKILL.md +130 -0
  178. package/skill-data/data-workflow/SKILL.md +17 -15
  179. package/skill-data/data-workflow/references/building-clean-tables.md +1 -1
  180. package/skill-data/document/SKILL.md +3 -3
  181. package/skill-data/git-sync/SKILL.md +5 -5
  182. package/skill-data/mbql/SKILL.md +17 -17
  183. package/skill-data/mbql/references/operators.md +4 -3
  184. package/skill-data/metadata/SKILL.md +78 -0
  185. package/skill-data/metadata/references/semantic-types.md +83 -0
  186. package/skill-data/native-sql/SKILL.md +118 -0
  187. package/skill-data/native-sql/references/template-tags.md +178 -0
  188. package/skill-data/transform/SKILL.md +6 -6
  189. package/skill-data/visualization/SKILL.md +3 -3
  190. package/skill-data/visualization/references/settings.md +2 -0
  191. package/dist/add-collection-Dek6kiRI.mjs +0 -11
  192. package/dist/auth-Kv2MRkRk.mjs +0 -22
  193. package/dist/capabilities-N0jo5U7S.mjs +0 -239
  194. package/dist/card-Bp58WEUF.mjs +0 -26
  195. package/dist/collection-D8TI20Ir.mjs +0 -23
  196. package/dist/dashboard-C9pQCnX6.mjs +0 -28
  197. package/dist/db-DWykmBOh.mjs +0 -28
  198. package/dist/document-DNDm8_Py.mjs +0 -22
  199. package/dist/error-5H_tcfL8.mjs +0 -227
  200. package/dist/field-CFt1-KDR.mjs +0 -21
  201. package/dist/get-CDLa6LiC.mjs +0 -50
  202. package/dist/git-sync-ByvjqSiy.mjs +0 -31
  203. package/dist/is-dirty-D7UMN0mt.mjs +0 -10
  204. package/dist/manifest-BVf8P4bl.mjs +0 -126
  205. package/dist/measure-CgFwtL1r.mjs +0 -25
  206. package/dist/metadata-ClehtgZj.mjs +0 -39
  207. package/dist/metadata-DplshwI3.mjs +0 -38
  208. package/dist/notice-DyVl5aYB.mjs +0 -206
  209. package/dist/segment-BPC725mo.mjs +0 -25
  210. package/dist/setting-DHYO-W5g.mjs +0 -20
  211. package/dist/snippet-DtLmHr2J.mjs +0 -22
  212. package/dist/table-B1iBqmNu.mjs +0 -22
  213. package/dist/transform-BuIooRQh.mjs +0 -31
  214. package/dist/transform-job-C3yz0krA.mjs +0 -25
  215. package/dist/transform-tag-CJD6mJUe.mjs +0 -21
  216. /package/dist/{body-flags-DWTTxJpP.mjs → body-flags-CgHgJBRC.mjs} +0 -0
  217. /package/dist/{command-augment-DdZIfx1V.mjs → command-augment-D9pI9Vbh.mjs} +0 -0
  218. /package/dist/{paginate-FVZUxL4J.mjs → paginate-CMqbqhMC.mjs} +0 -0
  219. /package/dist/{parameter-CiJ4CwWE.mjs → parameter-BZ6y-Gfs.mjs} +0 -0
  220. /package/dist/{render-BTKnWL0d.mjs → render-CkuFkWlQ.mjs} +0 -0
  221. /package/dist/{revision-message-flag-CHrJgFFx.mjs → revision-message-flag-CHzX0cqV.mjs} +0 -0
  222. /package/dist/{setting-m46MUtW5.mjs → setting-Cko6bE_w.mjs} +0 -0
  223. /package/dist/{transform-job-CtixL4An.mjs → transform-job-CtVziW85.mjs} +0 -0
  224. /package/dist/{transform-tag-rsIrckCM.mjs → transform-tag-wFiWmiyO.mjs} +0 -0
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: native-sql
3
+ description: Author native SQL queries with parameters (filter widgets) for the `mb` CLI. Native SQL is a query whose single stage is raw SQL (`mbql.stage/native`) instead of structured MBQL — the same query envelope, so it is pre-flight-validated and round-trips. Covers the shape, the four template-tag kinds (raw variable, field filter, snippet, card reference), the variable / optional-block / snippet / card-reference syntax, the field-filter-vs-variable decision, the field ref in a field-filter dimension, wiring a tag to a dashboard filter, and running with values. Triggers — "write a SQL question", "add a filter widget to my SQL", "parameterize this query", "use a field filter", "reference a saved question in SQL", "why does my variable return no rows".
4
+ allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
5
+ ---
6
+
7
+ # Native SQL
8
+
9
+ **Prefer a structured query.** Native SQL is a Metabase query whose single stage is raw SQL (`mbql.stage/native`) instead of structured MBQL (`mbql.stage/mbql`) — both are the same query envelope (`mbql`). Reach for a native stage only when a structured query genuinely can't express it — engine-specific functions, CTEs, window logic beyond `offset`, hairy hand-tuned SQL — or when the user asks for SQL. If you can write it as a structured stage, do.
10
+
11
+ General flag conventions, body-input precedence, `./.scratch`, and `mb uuid` mechanics live in `core` (`mb skills get core`).
12
+
13
+ ## The shape
14
+
15
+ A native `dataset_query` is a query with one **native stage** — the `lib/type: "mbql/query"` envelope, a numeric `database`, and a single `mbql.stage/native` stage carrying the SQL string (`native`) plus a `template-tags` map:
16
+
17
+ ```json
18
+ {
19
+ "lib/type": "mbql/query",
20
+ "database": 1,
21
+ "stages": [
22
+ {
23
+ "lib/type": "mbql.stage/native",
24
+ "native": "SELECT count(*) FROM orders WHERE {{status}} AND total > {{min_total}}",
25
+ "template-tags": { "status": { … }, "min_total": { … } }
26
+ }
27
+ ]
28
+ }
29
+ ```
30
+
31
+ This is the form a card stores and returns — author it. The CLI **pre-flight-validates** it — the envelope, the template-tag shapes, the field refs — through the usual `--print-schema → --dry-run → run` loop (`mbql`), and a saved card **round-trips** in exactly this shape: `mb card get <id> --full --json`, edit the `stages[0].native` string, send it straight back. Only the SQL string is opaque to pre-flight — a **SQL** syntax error surfaces just when you run it, not at `--dry-run`. A parameterless query needs no `template-tags` — just the `native` string.
32
+
33
+ You may see an older flat form in cards created long ago — `{database, type:"native", native:{query}}`. The server still accepts it (it normalizes to the above) but it skips pre-flight and doesn't round-trip — **don't author it**.
34
+
35
+ ## Parameters are template tags
36
+
37
+ Every `{{name}}` in the SQL must have a matching entry in the stage's `template-tags`, keyed by that name. **The three must agree exactly:** the `{{name}}` in SQL = the map key = the entry's `"name"` field. Names are case-sensitive (`{{Cat}}` ≠ `{{cat}}`). A `{{name}}` with no entry fails at run time; an unused entry is ignored.
38
+
39
+ Four kinds of tag, by `type`:
40
+
41
+ | Kind | `type` | SQL syntax | What it is |
42
+ | ------------------ | -------------------------------- | ----------------------------- | -------------------------------------------- |
43
+ | **Raw variable** | `text` `number` `date` `boolean` | `WHERE total > {{min_total}}` | a literal substituted into the SQL |
44
+ | **Field filter** | `dimension` | `WHERE {{status}}` (bare!) | a smart filter widget bound to a real column |
45
+ | **Snippet** | `snippet` | `{{snippet: Active Rows}}` | a reusable SQL fragment (`mb snippet`) |
46
+ | **Card reference** | `card` | `{{#42}}` or `{{#42-slug}}` | another saved query, as a subquery |
47
+
48
+ Give each tag an `id` — mint one per tag with `mb uuid` (never hand-write one). Wrap any clause that should be droppable when its value is empty in **`[[ … ]]`**, keyword and all: `[[AND {{status}}]]`, not `AND [[{{status}}]]`. Only one level of nesting; a query using several optional `[[AND …]]` blocks needs a real `WHERE` first (e.g. `WHERE true [[AND {{a}}]] [[AND {{b}}]]`).
49
+
50
+ ## The decision that matters: field filter vs. raw variable
51
+
52
+ This is the call agents get wrong. Default to a **field filter** whenever the tag filters a real table column.
53
+
54
+ - A **raw variable** (`{{x}}`) is a dumb literal splice. You write the operator yourself: `WHERE status = {{x}}`. It gives a plain text/number/date box, no dropdown, no date picker, and it's what powers computed bits that aren't a column (`LIMIT {{n}}`, a threshold, an interpolated identifier).
55
+ - A **field filter** (`type: dimension`) is a smart widget bound to a column via `dimension`. You write it **bare** — `WHERE {{status}}` — and Metabase expands it to the right SQL (`status IN (...)`, a `BETWEEN` for dates, etc.), driving a dropdown/date-picker sourced from the column's values. Writing `WHERE status = {{status}}` around a field filter **breaks the expansion** — the single most common native-SQL bug.
56
+
57
+ Field filters only bind to a **real, connected database column** — not an expression, not an aggregate, not a subquery/CTE column. If the thing you're filtering isn't a physical column, it has to be a raw variable.
58
+
59
+ ## Template-tag bodies (the two you author most)
60
+
61
+ **Field filter** — `dimension` binds a column, `widget-type` picks the widget:
62
+
63
+ ```json
64
+ "status": {
65
+ "id": "9ddca4ca-3906-83fd-bc6b-8480ae9ab05e",
66
+ "name": "status",
67
+ "display-name": "Status",
68
+ "type": "dimension",
69
+ "dimension": ["field", {}, 141],
70
+ "widget-type": "string/="
71
+ }
72
+ ```
73
+
74
+ **`dimension` is a field ref: `["field", {options}, <field-id>]`** — options object **second**, id **third**, exactly the `mbql` rule. The legacy `["field", <id>, null]` shape (id first) that the UI and older docs show is **rejected by pre-flight** here (`must be the field options object`). Send `{}` for the options; the server fills in a `lib/uuid`. The field id comes from `table get <id> --include fields`.
75
+
76
+ `widget-type` must suit the column's type and is a closed enum (same vocabulary as dashboard filter `type`): string ops (`string/=`, `string/!=`, `string/contains`, `string/starts-with`, …), number ops (`number/=`, `number/between`, `number/>=`, …), dates (`date/all-options`, `date/range`, `date/relative`, `date/month-year`, …), plus `category`, `id`, `boolean/=`, and the `location/*` set. Text column → a `string/*` or `category`; datetime → a `date/*`; numeric → a `number/*`. `date/all-options` is the most flexible date widget.
77
+
78
+ **Raw variable** — no `dimension`, no `widget-type`:
79
+
80
+ ```json
81
+ "min_total": {
82
+ "id": "35f1ecd4-d622-6d14-54be-750c498043cb",
83
+ "name": "min_total",
84
+ "display-name": "Minimum total",
85
+ "type": "number",
86
+ "required": true,
87
+ "default": "50"
88
+ }
89
+ ```
90
+
91
+ Snippet and card-reference bodies (and the full field list for every kind) are in `references/template-tags.md` — load it when you need them (`mb skills get native-sql --full`).
92
+
93
+ ## Snippets and card references
94
+
95
+ - **Snippet** (`{{snippet: Name}}`): a shared SQL fragment stored via `mb snippet create --body '{"name":"Active Rows","content":"status = '\''active'\''"}'` — `content` is bare SQL, no wrapping. Reuse it across queries; edit it once. The tag body carries `snippet-id` + `snippet-name`.
96
+ - **Card reference** (`{{#42}}`): inlines another saved query as a subquery — `SELECT * FROM {{#42}}` or `WITH x AS {{#42}} …`. The tag body carries `card-id`.
97
+ - **Neither takes a parameter value.** A referenced card runs with **its own saved defaults** — you can't override its parameters from the parent query. Snippets are static text. Only raw variables and field filters are user-fillable.
98
+
99
+ ## Wiring, defaults, and running
100
+
101
+ **Give a tag a default or a dropdown source** by declaring it in the card's `parameters` array (alongside `dataset_query`) — this is where `default`, and a `values_source_type` (`static-list` / `card`) live. Its `target` links back to the tag: `["dimension", ["template-tag", "status"]]` for a field filter, `["variable", ["template-tag", "min_total"]]` for a raw variable. (Metabase auto-derives basic `parameters` from the template tags, so you only declare them to add defaults or a value source.)
102
+
103
+ **Run a saved card with values** via `card query`, whose `--parameters` is a JSON array of `{type, target, value}` — same `target` grammar:
104
+
105
+ ```bash
106
+ mb card query 12 --parameters '[{"type":"string/=","target":["dimension",["template-tag","status"]],"value":"active"}]' --json
107
+ ```
108
+
109
+ **Expose it as a dashboard filter** by mapping a dashboard parameter to the tag on the dashcard — the mapping `target` is the same `["dimension",["template-tag","status"]]` (field filter) or `["variable",["template-tag","status"]]` (raw variable). The dashboard-side mechanics (the `parameters` array and `parameter_mappings`) live in `core`.
110
+
111
+ ## Don't
112
+
113
+ - Don't wrap a field filter in an operator (`WHERE col = {{ff}}`) — write it bare (`WHERE {{ff}}`).
114
+ - Don't write the field-filter `dimension` in the legacy `["field", id, null]` shape — use `["field", {}, id]` (options second).
115
+ - Don't author the flat `{type:"native", …}` form — send the native stage above.
116
+ - Don't use native SQL for DDL or multiple statements — the editor is read-only, single-statement; `CREATE`/`UPDATE`/`;`-chained SQL is unsupported. To materialize a table, use a `transform`.
117
+ - Don't expect `[[ ]]` to save you from a case/type mismatch — `WHERE plan = {{p}}` returns zero rows on a case-sensitive engine if the value's case is off; that's a value problem, not syntax.
118
+ - Don't reach for native when a structured query fits — you lose the engine-independence and readability of an `mbql.stage/mbql` stage.
@@ -0,0 +1,178 @@
1
+ # Template tags — full reference
2
+
3
+ Every template-tag body, the widget-type vocabulary, and the parameter-object shapes. The main skill covers the two you author most (field filter, raw variable); this is the rest plus the exhaustive field lists.
4
+
5
+ ## Template-tag bodies by `type`
6
+
7
+ The `template-tags` value is a map keyed by tag name; each entry's `name` must equal its key and the `{{name}}` in the SQL. `id` is a UUID — mint with `mb uuid`.
8
+
9
+ ### Raw variable — `text` / `number` / `date` / `boolean`
10
+
11
+ ```json
12
+ "min_total": {
13
+ "id": "<uuid>",
14
+ "name": "min_total",
15
+ "display-name": "Minimum total",
16
+ "type": "number",
17
+ "required": false,
18
+ "default": "50"
19
+ }
20
+ ```
21
+
22
+ | Field | Req | Notes |
23
+ | -------------- | --- | -------------------------------------------- |
24
+ | `name` | ✓ | equals map key and `{{name}}` |
25
+ | `display-name` | ✓ | label shown in the widget |
26
+ | `type` | ✓ | `text` \| `number` \| `date` \| `boolean` |
27
+ | `id` | — | UUID; supply one |
28
+ | `required` | — | `true` blocks the run until a value is given |
29
+ | `default` | — | value used when none passed (string form) |
30
+
31
+ SQL: `{{min_total}}`, spliced literally — you write the operator (`total > {{min_total}}`).
32
+
33
+ ### Field filter — `dimension`
34
+
35
+ ```json
36
+ "status": {
37
+ "id": "<uuid>",
38
+ "name": "status",
39
+ "display-name": "Status",
40
+ "type": "dimension",
41
+ "dimension": ["field", {}, 141],
42
+ "widget-type": "string/=",
43
+ "default": null,
44
+ "options": null,
45
+ "alias": null
46
+ }
47
+ ```
48
+
49
+ | Field | Req | Notes |
50
+ | ------------- | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
51
+ | `type` | ✓ | `"dimension"` |
52
+ | `dimension` | ✓ | field ref `["field", {}, <id>]` — options object second, id third (the `mbql` rule); the legacy `["field", <id>, null]` form is rejected by pre-flight |
53
+ | `widget-type` | ✓ | the widget/operator; must suit the column type (table below) |
54
+ | `default` | — | e.g. a value, or a `["2024-01-01","2024-12-31"]` range |
55
+ | `options` | — | filter options map (e.g. case sensitivity), usually `null` |
56
+ | `alias` | — | set when the column comes from an aliased table in the SQL |
57
+
58
+ SQL: bare — `WHERE {{status}}`. Never `WHERE status = {{status}}`. On write, send `{}` for the ref's options; the server fills a `lib/uuid` and the card reads back `["field", {"lib/uuid": "…"}, <id>]`.
59
+
60
+ ### Snippet — `snippet`
61
+
62
+ ```json
63
+ "snippet: Active Rows": {
64
+ "id": "<uuid>",
65
+ "name": "snippet: Active Rows",
66
+ "display-name": "Snippet: Active Rows",
67
+ "type": "snippet",
68
+ "snippet-name": "Active Rows",
69
+ "snippet-id": 5
70
+ }
71
+ ```
72
+
73
+ SQL: `{{snippet: Active Rows}}`. Create/manage the fragment with `mb snippet` (`content` is bare SQL). No user value.
74
+
75
+ ### Card reference — `card`
76
+
77
+ ```json
78
+ "#42": {
79
+ "id": "<uuid>",
80
+ "name": "#42",
81
+ "display-name": "#42",
82
+ "type": "card",
83
+ "card-id": 42
84
+ }
85
+ ```
86
+
87
+ SQL: `{{#42}}` or `{{#42-slug}}`, used where a table/subquery goes (`FROM {{#42}}`, `WITH x AS {{#42}}`). Runs with the referenced card's own defaults; no user value.
88
+
89
+ ### Source table — `table` (v59+)
90
+
91
+ A niche v59+ type that references a warehouse table by id (`{type: "table", table-id: <id>}`, optional `source-filters`) where a table/subquery goes — analogous to a card reference but pointing at a raw table. Absent on v0.58. Reach for a card reference (`card`) unless you specifically need a bare-table source tag.
92
+
93
+ ### Temporal unit — `temporal-unit`
94
+
95
+ A widget that lets the viewer pick the time bucket (day/week/month/…) for a datetime column. Body mirrors a field filter (`dimension` legacy ref, optional `alias`) with `type: "temporal-unit"`.
96
+
97
+ ## `widget-type` by column type
98
+
99
+ Closed enum — same vocabulary as a dashboard parameter `type`. Pick one whose family matches the bound column.
100
+
101
+ | Column type | Common widget-types |
102
+ | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
103
+ | Text / string | `string/=` `string/!=` `string/contains` `string/does-not-contain` `string/starts-with` `string/ends-with` `category` |
104
+ | Number | `number/=` `number/!=` `number/between` `number/>=` `number/<=` |
105
+ | Date / datetime | `date/all-options` `date/single` `date/range` `date/relative` `date/month-year` `date/quarter-year` |
106
+ | Boolean | `boolean/=` |
107
+ | ID / FK | `id` |
108
+ | Location (with matching semantic type) | `location/city` `location/state` `location/zip_code` `location/country` |
109
+
110
+ `date/all-options` gives the fullest date picker (single, range, relative). `category` yields a value-list dropdown for a low-cardinality text column.
111
+
112
+ ## Parameter object — declared vs. runtime
113
+
114
+ Same object, two contexts. `target` links the parameter to a template tag: `["dimension", ["template-tag", "<name>"]]` for a field filter, `["variable", ["template-tag", "<name>"]]` for a raw variable.
115
+
116
+ **Declared** — in the card's `parameters` array, to set a default or a dropdown source:
117
+
118
+ ```json
119
+ {
120
+ "id": "<uuid>",
121
+ "name": "status",
122
+ "slug": "status",
123
+ "type": "string/=",
124
+ "target": ["dimension", ["template-tag", "status"]],
125
+ "default": "active",
126
+ "values_source_type": "static-list",
127
+ "values_source_config": { "values": ["active", "churned", "trial"] }
128
+ }
129
+ ```
130
+
131
+ `values_source_type`: omit to pull live distinct values from the bound field; `"static-list"` + `values_source_config.values` for a fixed list; `"card"` + `{card_id, value_field, label_field}` to source from a query.
132
+
133
+ **Runtime** — passed to `card query --parameters`; carries a `value`, no source config:
134
+
135
+ ```json
136
+ { "type": "string/=", "target": ["dimension", ["template-tag", "status"]], "value": "active" }
137
+ ```
138
+
139
+ The runtime `type` is the value's type, not the tag's. Date ranges pass as `"value": ["2024-01-01", "2024-12-31"]`. Omit a parameter entirely to leave an optional (`[[ ]]`) clause out.
140
+
141
+ ## Full native card body
142
+
143
+ What `mb card create --file` consumes:
144
+
145
+ ```json
146
+ {
147
+ "name": "Active orders by status",
148
+ "display": "table",
149
+ "visualization_settings": {},
150
+ "dataset_query": {
151
+ "lib/type": "mbql/query",
152
+ "database": 1,
153
+ "stages": [
154
+ {
155
+ "lib/type": "mbql.stage/native",
156
+ "native": "SELECT status, count(*) FROM orders WHERE total > {{min_total}} [[AND {{status}}]] GROUP BY status",
157
+ "template-tags": {
158
+ "min_total": {
159
+ "id": "<uuid>",
160
+ "name": "min_total",
161
+ "display-name": "Minimum total",
162
+ "type": "number",
163
+ "default": "0"
164
+ },
165
+ "status": {
166
+ "id": "<uuid>",
167
+ "name": "status",
168
+ "display-name": "Status",
169
+ "type": "dimension",
170
+ "dimension": ["field", {}, 141],
171
+ "widget-type": "string/="
172
+ }
173
+ }
174
+ }
175
+ ]
176
+ }
177
+ }
178
+ ```
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: transform
3
- description: Author and run Metabase transforms via `mb` — body shape (native SQL + MBQL 5), create + run-with-wait, run inspection, dependencies, cancel, the `update`-vs-recreate iteration rule, the writable-keys-only PATCH contract, plus transform tags and tag-driven transform-job schedules. Load when the user touches transforms — "create a transform", "run a transform", "fix a failing transform", "list transform runs", "cancel a running transform", "manage transform tags", "run a transform job", or anything `mb transform …` / `mb transform-job …` / `mb transform-tag …`.
3
+ description: Author and run Metabase transforms via `mb` — body shape (native SQL or structured MBQL), create + run-with-wait, run inspection, dependencies, cancel, the `update`-vs-recreate iteration rule, the writable-keys-only PATCH contract, plus transform tags and tag-driven transform-job schedules. Load when the user touches transforms — "create a transform", "run a transform", "fix a failing transform", "list transform runs", "cancel a running transform", "manage transform tags", "run a transform job", or anything `mb transform …` / `mb transform-job …` / `mb transform-tag …`.
4
4
  allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
5
5
  ---
6
6
 
@@ -17,11 +17,11 @@ A transform has two halves:
17
17
  - `source` — the query to run (`type: "query"`, with `query.type` of `native` or `mbql`).
18
18
  - `target` — the warehouse destination (`type: "table"`, with `database`, `schema`, `name`).
19
19
 
20
- Native SQL is the simplest source and the easiest to author by hand. For an **MBQL 5** `source.query` (`lib/type: "mbql/query"`) — the body shape, the options-object-is-always-second clause rule, UUID minting, aggregation/order-by refs, naming aggregation output columns, the `--print-schema` → `--dry-run` validation loop, and the MBQL-5 pre-flight that `transform create`/`update` run (legacy MBQL 4 and native sources skip it) — see `mbql` (**`mb skills get mbql`**). Pull a sample MBQL body with `mb transform get <id> --full --json`. For a transform target, naming aggregation output columns matters more than usual: a bare `count` / `avg_2` becomes the warehouse column name.
20
+ Native SQL is the simplest source — author it as an `mbql.stage/native` stage (the SQL string sits at `source.query.stages[0].native`), the form below. For a **structured** `source.query` (an `mbql.stage/mbql` stage) — the options-object-is-always-second clause rule, UUID minting, aggregation/order-by refs, naming aggregation output columns, and the `--print-schema` → `--dry-run` validation loop — see `mbql` (**`mb skills get mbql`**). Both stage types are the `mbql/query` shape, so `transform create`/`update` pre-flight them (only the legacy flat forms skip it). Pull a sample body with `mb transform get <id> --full --json`. For a transform target, naming aggregation output columns matters more than usual: a bare `count` / `avg_2` becomes the warehouse column name.
21
21
 
22
22
  ## Create + run (native SQL)
23
23
 
24
- **Keep the SQL formatted.** Author it multi-line in `./.scratch/<name>.sql` and embed with `jq --rawfile` (jq ≥1.6, which JSON-encodes the file so newlines become `\n`). The stored `native.query` is what `mb transform get` and the Metabase editor render — a single-line blob is valid JSON but unreadable when anyone opens the transform. Single-quote the heredoc delimiter (`<<'SQL'`) so the shell leaves `$vars` in the query alone (e.g. Postgres `$1`, `$$`).
24
+ **Keep the SQL formatted.** Author it multi-line in `./.scratch/<name>.sql` and embed with `jq --rawfile` (jq ≥1.6, which JSON-encodes the file so newlines become `\n`). The stored SQL (`source.query.stages[0].native`) is what `mb transform get` and the Metabase editor render — a single-line blob is valid JSON but unreadable when anyone opens the transform. Single-quote the heredoc delimiter (`<<'SQL'`) so the shell leaves `$vars` in the query alone (e.g. Postgres `$1`, `$$`).
25
25
 
26
26
  ```bash
27
27
  cat > ./.scratch/user_counts_by_signup_year.sql <<'SQL'
@@ -36,7 +36,7 @@ SQL
36
36
  jq -n --rawfile q ./.scratch/user_counts_by_signup_year.sql \
37
37
  '{ name: "user_counts_by_signup_year",
38
38
  description: "Sample transform: counts users by year of signup",
39
- source: { type: "query", query: { type: "native", database: <db-id>, native: { query: $q } } },
39
+ source: { type: "query", query: { "lib/type": "mbql/query", database: <db-id>, stages: [{ "lib/type": "mbql.stage/native", native: $q }] } },
40
40
  target: { type: "table", database: <db-id>, schema: "public", name: "user_counts_by_signup_year" } }' \
41
41
  > ./.scratch/transform.json
42
42
 
@@ -124,7 +124,7 @@ SELECT …
124
124
  FROM public.orders
125
125
  SQL
126
126
  jq -n --rawfile q ./.scratch/orders.sql \
127
- '{ source: { type: "query", query: { type: "native", database: <db-id>, native: { query: $q } } } }' \
127
+ '{ source: { type: "query", query: { "lib/type": "mbql/query", database: <db-id>, stages: [{ "lib/type": "mbql.stage/native", native: $q }] } } }' \
128
128
  > ./.scratch/patch.json
129
129
  mb transform update <id> --file ./.scratch/patch.json --profile <name> --json
130
130
 
@@ -162,7 +162,7 @@ cat > ./.scratch/source.sql <<'SQL'
162
162
  <fixed SQL, formatted>
163
163
  SQL
164
164
  jq -n --rawfile q ./.scratch/source.sql \
165
- '{ source: { type: "query", query: { type: "native", database: <db-id>, native: { query: $q } } } }' \
165
+ '{ source: { type: "query", query: { "lib/type": "mbql/query", database: <db-id>, stages: [{ "lib/type": "mbql.stage/native", native: $q }] } } }' \
166
166
  > ./.scratch/source-patch.json
167
167
  mb transform update "$ID" --file ./.scratch/source-patch.json --profile <n> --json
168
168
 
@@ -27,7 +27,7 @@ Decide which relationship in the data matters most, then pick the chart. The sha
27
27
  - **Compare a measure across categories** → `bar` (vertical). Use `row` (horizontal bar) when labels are long or there are many categories. Sort by value unless the dimension has a natural order.
28
28
  - **Change over time / trend** → `line` for a continuous series; `bar`/`area` for a few discrete periods. Two measures on unlike scales → `combo` (line + bar, dual-axis) — only when the metrics are genuinely related.
29
29
  - **Part-to-whole, one snapshot** → `pie`, but only for a meaningful whole with **≤5 slices**; beyond that use a sorted `bar`/`row`. Composition over time → stacked `area`/`bar`.
30
- - **Distribution / spread / outliers** → `boxplot` (especially comparing several groups).
30
+ - **Distribution / spread / outliers** → a `bar` histogram (bin the measure — see `mbql` binning); on **v59+** servers `boxplot` compares several groups' spread directly.
31
31
  - **Correlation between two measures** → `scatter` (a third measure → bubble size).
32
32
  - **Sequential additive contributions** (start → +/− steps → total) → `waterfall`.
33
33
  - **Stage drop-off in an ordered, cumulative funnel** → `funnel`.
@@ -35,7 +35,7 @@ Decide which relationship in the data matters most, then pick the chart. The sha
35
35
  - **Geographic** → `map`: region/choropleth (a region dimension + a measure), pin (lat + long), or grid/heat (coordinates + measure).
36
36
  - **Precise values, many columns, mixed types, or no chart fits** → `table`; `pivot` for a cross-tab of two dimensions; `object` for a single record's detail.
37
37
 
38
- Valid `display` values — the registered visualizations: `table`, `bar`, `line`, `area`, `row`, `pie`, `scalar`, `smartscalar`, `combo`, `pivot`, `funnel`, `map`, `scatter`, `waterfall`, `progress`, `gauge`, `object`, `sankey`, `boxplot`. The API types `display` as a plain string and accepts any value — it renders an unknown one as nothing. (`scalar` **is** the "Number" viz — `display: number` is a legacy serialization alias, not a registered visualization; use `scalar`. `list` exists but is hidden — don't pick it. `heading`/`text`/`link`/`iframe`/`action` are dashcard virtuals, not standalone cards — see references.) A typo like `bargraph`/`linechart` is accepted and renders blank — the most common "why is my chart blank" cause.
38
+ Valid `display` values — the registered visualizations: `table`, `bar`, `line`, `area`, `row`, `pie`, `scalar`, `smartscalar`, `combo`, `pivot`, `funnel`, `map`, `scatter`, `waterfall`, `progress`, `gauge`, `object`, `sankey`. The API types `display` as a plain string and accepts any value — it renders an unknown one as nothing. (`boxplot` is registered only on **v59+** servers — older ones render it blank; use a `bar` histogram for distributions instead. `scalar` **is** the "Number" viz — `display: number` is a legacy serialization alias, not a registered visualization; use `scalar`. `list` exists but is hidden — don't pick it. `heading`/`text`/`link`/`iframe`/`action` are dashcard virtuals, not standalone cards — see references.) A typo like `bargraph`/`linechart` is accepted and renders blank — the most common "why is my chart blank" cause.
39
39
 
40
40
  ## Step 2 — bind data columns and set options
41
41
 
@@ -53,7 +53,7 @@ Valid `display` values — the registered visualizations: `table`, `bar`, `line`
53
53
  | `row` | as bar; prefer for long/many category labels | `graph.dimensions`, `graph.metrics` |
54
54
  | `scatter` | two numeric measures (correlation) | `graph.dimensions`, `graph.metrics` (`scatter.bubble` opt) |
55
55
  | `waterfall` | exactly 1 dimension + ≥1 measure; sequential | `graph.dimensions` (1), `graph.metrics` (1) |
56
- | `boxplot` | ≥3 cols, ≥2 dimensions, ≥1 measure | `graph.dimensions`, `graph.metrics` |
56
+ | `boxplot` _(v59+)_ | ≥3 cols, ≥2 dimensions, ≥1 measure | `graph.dimensions`, `graph.metrics` |
57
57
  | `pie` | ≥2 rows, ≥2 cols, ≥1 dimension + ≥1 measure; ≤~5 slices | `pie.dimension`, `pie.metric` |
58
58
  | `funnel` | 2 columns (stage + value); ordered stages | `funnel.dimension`, `funnel.metric` |
59
59
  | `map` (region) | a string/region dimension + a measure | `map.region`, `map.dimension`, `map.metric` |
@@ -104,6 +104,8 @@ Horizontal bars — use when category labels are long or numerous. Here `graph.d
104
104
 
105
105
  ## boxplot
106
106
 
107
+ _Registered only on **v59+** servers — older ones render `display: boxplot` blank; use a `bar` histogram there._
108
+
107
109
  Use for distribution/spread/outliers, especially across several groups. Needs **unaggregated** rows. **Use for:** ≥3 columns, ≥2 dimensions, ≥1 measure. **Required:** `graph.dimensions`, `graph.metrics`. X-scale is `"ordinal"`.
108
110
 
109
111
  | Key | Type | Values | Default |
@@ -1,11 +0,0 @@
1
- import "./notice-DyVl5aYB.mjs";
2
- import "./error-5H_tcfL8.mjs";
3
- import "./command-augment-DdZIfx1V.mjs";
4
- import "./runtime-BJtuxWM8.mjs";
5
- import "./capabilities-N0jo5U7S.mjs";
6
- import "./parse-id-D4LeTUsP.mjs";
7
- import "./poll-BpAJpvb-.mjs";
8
- import "./poll-task-TilgciQn.mjs";
9
- import { SyncSettingsUpdateResult, add_collection_default, setCollectionRemoteSynced, syncSettingsUpdateView } from "./add-collection-C-t9SQBk.mjs";
10
-
11
- export { add_collection_default as default };
@@ -1,22 +0,0 @@
1
- import "./command-augment-DdZIfx1V.mjs";
2
- import { defineCommandGroup } from "./group-BNE_RiH5.mjs";
3
-
4
- //#region src/commands/auth/index.ts
5
- var auth_default = defineCommandGroup({
6
- name: "auth",
7
- description: "Authenticate against a Metabase instance",
8
- defaultCommand: "login",
9
- skills: [{
10
- skill: "core",
11
- purpose: "authentication and named profiles"
12
- }],
13
- subCommands: {
14
- login: () => import("./login-Bt6j6yBM.mjs").then((m) => m.default),
15
- status: () => import("./status-CmRgHTrV.mjs").then((m) => m.default),
16
- list: () => import("./list-CvhVYOVl.mjs").then((m) => m.default),
17
- logout: () => import("./logout-ANkL02p0.mjs").then((m) => m.default)
18
- }
19
- });
20
-
21
- //#endregion
22
- export { auth_default as default };