REFSmashGL Reference · v1.0-rc1

The whole language fits on one page.

A SmashGL card has three concerns: goal (what success looks like), data (where values come from), and presentation (how to display it). Clauses can appear in any order. The runtime parses them into a canonical IR, evaluates against your data, and renders the result.

01Structure Goal · Data · Presentation.

Three concerns — any order.

// Goal — what success looks like
GOAL      <verb> <metric> [to|by] [<op>] <value>[<unit>] <time-phrase> [SOFT|HARD]
          [AND|OR <verb> <metric> ...]
[COMPARE   <mode>]
[TYPE      cumulative | ratio | level]
[DIRECTION higher | lower]
[FORMAT    percent | currency | number]
[SMOOTH    rolling7 | rolling14 | rolling30 | ema7 | ema14]
[WINDOW    <time-phrase>]   // standalone — only when GOAL is absent

// Data — live binding
SOURCE    <namespace>.<table>.<column> [AS <alias>] [, ...]
          [WHERE    <field> <op> <value> [AND ...]]
          [GROUP BY <dimension>]
          [ORDER BY <field> [ASC|DESC]]
          [LIMIT    <n>]
  // — OR inline static data —
DATA      <alias> = <json-value>
[PREVIOUS  <json-value>]

// Presentation — visualization type, flags, title
SMASH     <viz> [WITH <flag>, <flag>, ...] [TITLED "<title>"]
02Clauses Each clause, in order.

Ten keywords. That's the whole language.

2.1

SMASH

Declares the visualization, which flags are active, and the card title.

SMASH <viz> [WITH <flag>[, <flag>]...] [TITLED "<title>"]
vizrenders as
metricHero number with OKR goal block and vs-prior pill.
sparklineHero number + delta pill + small trend line.
chartFull-width chart variant (alias for sparkline).
barHorizontal bar chart with optional goal line.
gaugeArc / dial showing progress toward a goal.
tableRanked rows.
badgeSimple large-number display.

FLAGS · TREND · FORECAST · ALERT · RISK · GAP

No WITH clause → all applicable flags active by default. WITH <flag>, <flag> → only listed flags active. Flags requiring a GOAL are silently inert without one.

Custom ALERT colors — provide three hex values inline: SMASH metric WITH alert(#dc2626, #d97706, #16a34a). Fewer than 3 valid values → default palette.

SHOW AS is accepted as a verbose synonym for SMASH and produces identical IR.

2.2

GOAL

First-class outcome. Verb-based. Drives every goal-aware indicator — attainment, forecast, alert, gap, risk.

// canonical verbs
GOAL grow revenue by +15% this month
GOAL hit revenue >= $50,000 this month
GOAL reduce refund_rate to <= 2% this month
GOAL hold uptime >= 99.98% this month
GOAL cap ad_spend <= $5,000 this week

// SOFT / HARD commitment suffix
GOAL grow sessions to >= 50000 this month SOFT
GOAL hit revenue >= $50,000 this month HARD

// compound — AND requires all; OR requires any
GOAL hit revenue >= $15,000 AND hit orders >= 300 this month
GOAL grow revenue by +20% OR hit gross_profit >= $20,000 this month
verbdirectiontypical useimplied operator
growhigher-is-betterRevenue, sessions, orders>=
reducelower-is-betterActively shrinking: refund rate, churn<=
holdmaintainPass/fail thresholds: uptime SLA, conversion floor>=
hitreach an absolutePoint-in-time targets: revenue ≥ $50K>=
capenforce a ceilingBudget caps: ad spend ≤ $5K<=

Surface synonyms are accepted at parse time and normalized to canonical: increase/raise/boost/drive/lift/scalegrow · decrease/lower/cut/shrink/minimize/trim/dropreduce · maintain/sustain/keep/stay/ensurehold · reach/achieve/target/attainhit · ceilingcap.

Time phrases are embedded directly in the GOAL clause:

phrasewindow
this weekCurrent calendar week (week-start configurable; default Sunday).
this monthFirst of current month → today.
this quarterStart of current fiscal/calendar quarter → today.
this yearJanuary 1 → today.
last N daysRolling N-day window ending today. over last N days is identical.
last N weeksRolling N-week window.
from <date> to <date>Fixed ISO date range.
since <date>From ISO date to today.

Values accept: $50,000 (currency), 99.98% (percent), +15% (relative, +N% above comparison), 50000 (plain number). Comma thousand-separators are accepted.

2.3

SOURCE

Declares one or more fully-qualified data paths and binds them to local aliases.

// single column with alias
SOURCE shopify.sales.net_sales AS revenue

// multiple columns (comma-separated)
SOURCE shopify.sales.net_sales AS revenue,
       shopify.sales.gross_sales,
       shopify.sales.orders

// continuation clauses refine the source
SOURCE shopify.sales.gross_sales AS products
       WHERE    channel = "online_store"
       GROUP BY product_title
       ORDER BY gross_sales DESC
       LIMIT    10
clausepurpose
WHERE <field> <op> <value>Filter rows. Operators: =, !=, >, >=, <, <=, IN, NOT IN, CONTAINS. Chain with AND.
GROUP BY <dimension>Group by a categorical dimension (for bar, table) or a time granularity (for sparkline, chart).
ORDER BY <field> ASC|DESCSort results.
LIMIT <n>Cap row count — used by table.

Confirmed namespaces: shopify.sales (net_sales, gross_sales, gross_profit, orders, net_items_sold, refund_rate) · shopify.sessions (online_store_visitors, uptime_pct). Other namespaces work if your runtime is configured with the appropriate emitter.

IR note (v1.0-rc1): GROUP BY day|week|month|quarter|year is the surface form for the IR's granularity field on SourceBinding. SQL emitters pair it with timeField (defaults to created_at) to render DATE_TRUNC(<granularity>, <timeField>).

2.4

DATA

Inline static values instead of a live backend. Useful for demo cards, fixture cards, and one-off displays.

// single-row — object
DATA     revenue = {"net_sales": 47300, "gross_sales": 50600, "orders": 847}
PREVIOUS           {"net_sales": 41800, "gross_sales": 44200, "orders": 723}

// multi-row — array (bar charts)
DATA     returns_total = [
           {"period": "Week 1", "returns_total": 2650},
           {"period": "Week 2", "returns_total": 2300},
           {"period": "Week 3", "returns_total": 3100},
           {"period": "Week 4", "returns_total": 1890}
         ]
2.5

WINDOW

Standalone time phrase — used when no GOAL clause is present. When GOAL is present, the time phrase lives inside GOAL and WINDOW is rarely needed.

syntaxperiod
WINDOW this weekNamed — from start of current week to today.
WINDOW this monthNamed — from the 1st to today.
WINDOW this quarterNamed — from start of current quarter to today.
WINDOW this yearNamed — from January 1.
WINDOW last N daysRolling — last N days, ending today.
WINDOW over last N weeksRolling — last N weeks.
WINDOW since 2026-03-01Fixed start — rolls to today.
WINDOW from 2026-03-01 to 2026-03-15Fixed range — both ends defined.

FORECAST · RISK · GAP (time component) — require a window with a defined end. Inactive for rolling windows.

2.6

COMPARE

The comparison period — part of the question, not derived after the fact. Default is previousPeriod with no keyword needed.

modecomparison period
previousPeriodEqual-length window immediately before — default; no clause needed.
previousYearSame date range, twelve months earlier. Best for seasonal businesses.
sameDayLastWeekSame dates, shifted back seven days. Best for short rolling windows.
samePeriodLastYearSame named period last year — Feb 2026 → Feb 2025. Named windows only.
samePeriodLastMonthSame named period last month. Named windows only.

Default alignment: elapsed. For in-progress periods, the comparison window is auto-truncated to match the elapsed portion. "This month vs last year" on the 13th compares the 1st–13th both years — not the full prior month.

IR alignment override: the IR exposes alignment: "calendar-full" as an alternative — useful when a card should compare against the full prior calendar period regardless of how much of the current window has elapsed. Surface authoring stays on the elapsed default.

2.7

TYPE

Declares the nature of the metric — affects forecast extrapolation.

valuemeaningforecast
cumulativePeriod total that grows over time.Linear extrapolation — currentValue / periodProgress.
ratioRunning value — the metric IS the final value at any point.Current value — no extrapolation.
levelSnapshot value at a point in time.Current value — no extrapolation.

Inferred when omitted: column names containing rate, uptime, pct, percent, aov, cpa, cpc, roasratio. Everything else → cumulative. Declared TYPE always overrides.

2.8

DIRECTION

Whether higher or lower values are better. Inverts attainment, gap sign, and TREND pill colour.

valuemeaningattainment formula
higherHigher is better — default.currentValue / goal × 100
lowerLower is better. Use with <= or < goal operators.goal / currentValue × 100

Inferred when omitted: column names containing refund, return, churn, abandon, cost, bouncelower. The reduce and cap verbs also imply lower. TREND pill colour is inverted for lower — green means decreased.

2.9

FORMAT

Explicitly declares the display unit. Optional — inferred from column metadata when omitted.

valuedisplaynotes
percentAppends %, 2 decimal places.Use with TYPE ratio or DIRECTION lower.
currencyTenant's currency symbol.Same as auto-inferred for net_sales, gross_sales, etc.
numberPlain number — 1,200 or 1.2k.Forces plain display on an ambiguous column.

Most commonly needed when a rate metric returns a raw decimal but should display as a percentage — e.g. 0.0181.80%.

2.10

SMOOTH

Smoothing belongs to the query, not the renderer.

valuealgorithm
rolling7 / 14 / 30N-day rolling average — even weighting.
ema7 / ema14Exponential moving average — recent days weighted more heavily.

SMOOTH affects the trend line only — never the headline KPI. Only effective when the card renders a sparkline.

03Examples Whole queries — annotated.

Nine queries that exercise the full language.

Revenue · monthly target, vs. last year

Ex. 01 · metric + ALERT

GOAL    hit revenue >= $50,000 this month
COMPARE previousYear
SOURCE  shopify.sales.net_sales AS revenue, shopify.sales.gross_sales
SMASH   metric WITH alert TITLED "March Revenue"

Orders · rolling 30 days, grow 15%

Ex. 02 · metric + TREND + ALERT

GOAL    grow orders by +15% over last 30 days
COMPARE previousPeriod
SOURCE  shopify.sales.orders AS orders
SMASH   metric WITH trend, alert TITLED "Orders"

Top products · ranked table

Ex. 03 · table + GROUP BY + ORDER BY + LIMIT

WINDOW  last 90 days
SOURCE  shopify.sales.gross_sales AS products
        GROUP BY product_title
        ORDER BY gross_sales DESC
        LIMIT    10
SMASH   table TITLED "Top Products (90d)"

Refund rate · lower is better, percent display

Ex. 04 · TYPE ratio + DIRECTION lower + FORMAT

GOAL      reduce refund_rate to <= 2% this month
TYPE      ratio
SOURCE    shopify.sales.refund_rate AS refund_rate
SMASH     metric WITH trend, alert TITLED "Refund Rate"

Compound goal · revenue AND orders

Ex. 05 · compound GOAL with AND

GOAL    hit revenue >= $15,000 AND hit orders >= 300 this month
SOURCE  shopify.sales.net_sales AS revenue,
        shopify.sales.orders AS orders
SMASH   metric WITH alert, forecast TITLED "Monthly OKR"

Uptime SLA · hold threshold

Ex. 06 · hold verb + TYPE ratio

GOAL      hold uptime >= 99.98% this month
TYPE      ratio
SOURCE    shopify.sessions.uptime_pct AS uptime
SMASH     metric WITH alert TITLED "Uptime SLA"

Static / demo data

Ex. 07 · DATA with PREVIOUS

GOAL     hit revenue >= $15,000 this month
DATA     revenue = {"net_sales": 47300, "gross_sales": 50600, "orders": 847}
PREVIOUS            {"net_sales": 41800, "gross_sales": 44200, "orders": 723}
SMASH    metric WITH alert TITLED "Revenue (Demo)"

Sparkline · 30-day trend with smoothing

Ex. 08 · sparkline + SMOOTH + GROUP BY day

WINDOW  over last 30 days
SMOOTH  rolling7
SOURCE  shopify.sales.net_sales AS revenue
        GROUP BY day
        ORDER BY day ASC
SMASH   sparkline WITH trend TITLED "Revenue Trend"

Ad spend · weekly budget cap

Ex. 09 · cap verb + gauge

GOAL    cap ad_spend <= $5,000 this week
SOURCE  shopify.marketing.ad_spend AS ad_spend
SMASH   gauge WITH alert TITLED "Weekly Ad Budget"
04Validation Errors and warnings.

When the parser refuses, and when it just whispers.

A query is valid when

  • Either a SOURCE or DATA clause is present.
  • A SMASH clause is present.
  • Some time phrase is resolvable — either embedded in GOAL (recommended) or in a standalone WINDOW clause.
  • If GOAL is present, every metric it references must be available in the data binding.
  • <viz> in SMASH is one of metric · sparkline · chart · bar · gauge · badge · table.
  • DATA requires a value (object or array); the alias on the left of = is the binding name.
  • Compound goals must use either all AND or all OR — mixing is rejected.
  • FORMAT must be one of percent, currency, number — any other value is a parse error.

Warnings (the query still runs)

  • FORECAST with a rolling window — ignored.
  • RISK with a rolling window — ignored.
  • GAP time component with a rolling window — value remnant only.
  • TREND on sparkline / chart without day-level GROUP BY in SOURCE — trend line omitted; comparison pill still shown on metric / badge.
  • TREND with DATA (no time-series available) — trend line omitted.
  • TYPE ratio + FORECAST — forecast renders as current value; a warning is surfaced.
  • DIRECTION lower with a relative +N% goal — prefer absolute goals (reduce X to <= N) for lower-is-better cases.
  • samePeriodLastYear / samePeriodLastMonth with rolling windows — falls back to previousPeriod.
  • DIRECTION lower with a relative +N% goal — the sign-vs-direction interplay is ambiguous; prefer absolute goals (reduce X to <= N) for lower-is-better cases.

That's the whole language. The rest is rendering.