add-malli-schemas
Efficiently add Malli schemas to API endpoints in the Metabase codebase with proper patterns, validation timing, and error handling
Template tags for native SQL questions written through question_write's `native` — tag kinds, field-filter vs raw-variable, the template_tags shape, widget types, [[ ]] optional blocks, wiring tags to dashboards. Read before first passing template_tags. Triggers — "add a filter
$ npx -y skills add metabase/metabase --skill native-parameters --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/native-parametersContext preview
The summary Claude sees to decide when to auto-load this skill.
Template tags for native SQL questions written through question_write's `native` — tag kinds, field-filter vs raw-variable, the template_tags shape, widget types, [[ ]] optional blocks, wiring tags to dashboards. Read before first passing template_tags. Triggers — "add a filter
name: native-parameters description: Template tags for native SQL questions written through question_write's `native` — tag kinds, field-filter vs raw-variable, the template_tags shape, widget types, [[ ]] optional blocks, wiring tags to dashboards. Read before first passing template_tags. Triggers — "add a filter widget to my SQL", "parameterize this query", "field filter", "why does my variable return no rows", "wire a dashboard filter to a SQL card".
Prefer MBQL (`execute_query` + `question_write` `query`, validated server-side). Use `native` only for what MBQL can't express (engine-specific functions, CTEs, window functions) or when the user asks for SQL: a raw-SQL card can't take a dashboard filter until that filter is a template tag, while an MBQL card wires as-is.
question_write {"method": "create", "name": "Orders by status",
"native": {"database_id": 1,
"sql": "SELECT status, count(*) FROM orders WHERE {{category}} AND total > {{min_total}} GROUP BY status",
"template_tags": {
"category": {"type": "dimension", "field_id": 18, "widget_type": "string/=", "display_name": "Category"},
"min_total": {"type": "number", "display_name": "Minimum total", "default": 0}}}}Every `{{name}}` in the SQL is a tag. The server extracts them; `template_tags` configures them, keyed by the exact case-sensitive name — naming a tag absent from the SQL is an error. Never supply tag ids (the server mints them). Unconfigured tags are plain text variables.
Default to a **field filter** (`"type": "dimension"`) whenever the tag filters a real table column.
SELECT count(*) FROM orders WHERE {{status}} -- works
SELECT count(*) FROM orders o WHERE {{status}} -- fails: orders.status is hidden by the alias"tag_name": {"type": "dimension" | "temporal-unit" | "text" | "number" | "date" | "boolean",
"field_id": <numeric id or 21-char entity_id>, // required for dimension / temporal-unit
"widget_type": "string/=", // required for dimension
"display_name": "Label", // optional
"required": true, // optional; blocks the run until a value is given
"default": "Gadget"} // optionalField ids: `browse_data {"action": "get_fields", "table_ids": [<table id>]}`. `widget_type` by column type:
| Column type | widget_type | |---|---| | Text | `string/=` `string/!=` `string/contains` `string/does-not-contain` `string/starts-with` `string/ends-with` `category` | | Number | `number/=` `number/!=` `number/between` `number/>=` `number/<=` | | Date/datetime | `date/all-options` (fullest picker) `date/single` `date/range` `date/relative` `date/month-year` `date/quarter-year` | | Boolean | `boolean/=` | | PK/FK | `id` | | Location semantic type | `location/city` `location/state` `location/zip_code` `location/country` |
Round-trip: `get_content` returns `template_tags` in the stored shape (`display-name`, `widget-type`, a `dimension` ref); `question_write` accepts it back verbatim. Don't author that shape or hand-mint ids — `field_id` is the write dialect.
Wrap any clause that should drop when its value is empty, keyword included: `WHERE true [[AND {{category}}]] [[AND total > {{min_total}}]]`. One nesting level; several optional `AND` blocks need a real `WHERE` first. A `required` tag or one with a `default` always has a value, so its clause never drops. `[[ ]]` doesn't fix a case/type mismatch: `WHERE plan = {{p}}` returns zero rows on a case-sensitive engine when the value's case is off.
**Run** — `run_saved_question` takes `{id | slu
Metabase is the easy, open-source way for everyone in your company to ask questions and learn from data.
Repo: metabase/metabase
Efficiently add Malli schemas to API endpoints in the Metabase codebase with proper patterns, validation timing, and error handling
Add OpenTelemetry tracing spans to Clojure code following Metabase tracing conventions. Use when instrumenting backend code with trace coverage.
Add product analytics events to track user interactions in the Metabase frontend
Evaluate Clojure code via nREPL using clj-nrepl-eval. Use this when you need to test code, check if edited files compile, verify function behavior, or interact…
Review Clojure and ClojureScript code changes for compliance with Metabase coding standards, style violations, and code quality issues. Use when reviewing pull…
Guide Clojure and ClojureScript development using REPL-driven workflow, coding conventions, and best practices. Use when writing, developing, or refactoring…