From 027cfc760e37a89e12831580685ed06d899b4d26 Mon Sep 17 00:00:00 2001 From: Jax Liu Date: Thu, 14 May 2026 18:41:56 +0800 Subject: [PATCH 1/3] docs: cube skills + user-facing docs (Phase G) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires cube knowledge into the wren-usage skill and user-facing docs. Final phase of the cube rollout (impl-cube-skills.md). Skill: * skills/wren-usage/SKILL.md — new Cube Query Workflow section, Aggregation decision tree, extra command-decision-tree line; version bumped 2.2 → 2.3 * skills/wren-usage/references/wren-sql.md — new "Cube query SQL generation" section (generated SQL pattern + key points + how to diagnose cube SQL errors with --sql-only) * skills/wren-usage/references/memory.md — new "Cube schema items" subsection inside Schema context * skills/wren-generate-mdl/SKILL.md — context init directory tree now lists cubes/; a one-line "When to define cubes" hint links to the Cube guide Docs: * README.md — "Why WrenAI?" gains a pre-aggregation cubes callout * core/wren/README.md — Quick start gains step 4a (cubes) * docs/core/reference/cli.md — new "wren cube" command section with flag table, supported granularities, and operators * docs/core/get_started/quickstart.md — new optional step 8 demoing cube query * docs/core/guides/modeling/overview.md — Cube added as a core modeling object between View and Memory; rule-of-thumb list updated * docs/core/guides/modeling/cube.md — new guide parallel to model.md / view.md / relation.md (YAML structure, fields, time granularity, derived measures, filter operators, CLI, WASM, validation) Verified (no edit needed): * core/wren-core-wasm/AGENT_GUIDE.md — PR #2278's Cube Query API section is already present Trail: PR #1574 (cube types), PR #2264 (validate_cubes), PR #2265 (cube_query_to_sql), PR #2276 (cleanup), PR #2277 (PyO3 + CLI), PR #2278 (WASM + AGENT_GUIDE), now this PR (skills + docs). Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 2 + core/wren/README.md | 15 ++ docs/core/get_started/quickstart.md | 21 +++ docs/core/guides/modeling/cube.md | 184 +++++++++++++++++++++++ docs/core/guides/modeling/overview.md | 19 +++ docs/core/reference/cli.md | 69 +++++++++ skills/wren-generate-mdl/SKILL.md | 11 +- skills/wren-usage/SKILL.md | 94 +++++++++++- skills/wren-usage/references/memory.md | 18 +++ skills/wren-usage/references/wren-sql.md | 48 ++++++ 10 files changed, 478 insertions(+), 3 deletions(-) create mode 100644 docs/core/guides/modeling/cube.md diff --git a/README.md b/README.md index 9eec4f31f0..3dbaae2c1a 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ WrenAI is the open context layer that fills that gap. You model your business in A Rust engine powered by [Apache DataFusion](https://datafusion.apache.org/) translates the modeled SQL and runs it against 20+ data sources (PostgreSQL, BigQuery, Snowflake, Spark, etc.). Use it as a Python SDK, a CLI, a WASM module in the browser, or as building blocks for agent skills. +**Pre-aggregation cubes** — model business metrics once (revenue, order count, retention) with measures, dimensions, and time grains. AI agents query cubes with a structured input instead of hand-writing `GROUP BY` / `DATE_TRUNC` SQL, cutting error rates substantially on small / local models. See the [Cube guide](./docs/core/guides/modeling/cube.md). + ## Quick start The fastest path is to let an AI coding agent (Claude Code, Cursor, Aider, etc.) drive the install: diff --git a/core/wren/README.md b/core/wren/README.md index 8f77e4a5b2..aa944bbb86 100644 --- a/core/wren/README.md +++ b/core/wren/README.md @@ -104,6 +104,21 @@ wren --sql 'SELECT order_id FROM "orders" LIMIT 10' For the full CLI reference and per-datasource connection field reference, see [`docs/cli.md`](docs/cli.md) and [`docs/connections.md`](docs/connections.md). +**4a. (Optional) Aggregation queries with cubes** — define cubes under `cubes/`, +then query them with a structured input instead of writing `GROUP BY` SQL by hand: + +```bash +wren cube list +wren cube describe order_metrics +wren cube query --cube order_metrics --measures revenue --time-dimension "created_at:month" +``` + +The translator produces `DATE_TRUNC` / `GROUP BY` / `WHERE` clauses for you and +runs them through the same engine path as `wren --sql`. See the +[Cube guide](../../docs/core/guides/modeling/cube.md) for full YAML structure +and the [CLI reference](../../docs/core/reference/cli.md#cube-commands) for all +flags. + **5. (Optional) Configure security policy** — create `~/.wren/config.json`: ```json diff --git a/docs/core/get_started/quickstart.md b/docs/core/get_started/quickstart.md index af1e3ce653..acbb85e160 100644 --- a/docs/core/get_started/quickstart.md +++ b/docs/core/get_started/quickstart.md @@ -260,6 +260,27 @@ The more you ask, the smarter the system gets — each stored query improves fut --- +## Step 8 — Query a cube (optional) + +If your MDL defines cubes, use the cube CLI for aggregation queries — agents +don't have to hand-write `GROUP BY` / `DATE_TRUNC` SQL: + +```bash +wren cube list + +wren cube query \ + --cube order_metrics \ + --measures revenue \ + --time-dimension "created_at:month" +``` + +Cube queries are the recommended path for aggregation when a cube covers the +question. Lower error rate, especially on small / local models. See the +[Cube guide](../guides/modeling/cube.md) for the YAML structure and the +[CLI reference](../reference/cli.md#wren-cube--pre-aggregation-queries) for all flags. + +--- + ## What's in the project After setup, your project directory looks like this: diff --git a/docs/core/guides/modeling/cube.md b/docs/core/guides/modeling/cube.md new file mode 100644 index 0000000000..2c0b6eca01 --- /dev/null +++ b/docs/core/guides/modeling/cube.md @@ -0,0 +1,184 @@ +# Cube + +A **Cube** is a pre-aggregation semantic layer object that defines reusable +aggregations on top of a Model or View. Clients send a structured `CubeQuery` +(measures, dimensions, optional time bucket + filters); the engine produces +`SELECT … GROUP BY` SQL and runs it through the same path as `wren --sql`. + +## When to use + +Define a cube when you want to: + +- run aggregation queries (`SUM`, `COUNT`, `AVG`) grouped by dimensions +- group by time (`year` / `quarter` / `month` / `week` / `day` / `hour` / `minute`) +- share business metrics between AI agents, BI dashboards, and the browser SDK +- expose drill-down hierarchies for dashboard navigation + +Cubes are particularly useful for AI agents: instead of writing `GROUP BY` and +`DATE_TRUNC` SQL by hand (and getting it wrong on small / local models), an +agent picks a measure + dimension + granularity from the cube definition and +the translator builds the SQL. + +## Structure + +Each cube lives in its own file under `cubes/` as `cubes/.yml`. The +YAML uses `snake_case`; `wren context build` converts to `camelCase` for +the engine. + +```yaml +# cubes/order_metrics.yml +name: order_metrics +base_object: orders # name of a defined Model or View + +measures: + - name: revenue + expression: "SUM(o_totalprice)" + type: DOUBLE + - name: order_count + expression: "COUNT(*)" + type: BIGINT + - name: avg_order_value + expression: "revenue / order_count" # ← derived measure (auto-inlined) + type: DOUBLE + +dimensions: + - name: status + expression: "o_orderstatus" + type: VARCHAR + +time_dimensions: + - name: created_at + expression: "o_orderdate" + type: DATE + +hierarchies: + time_drill: + - created_at # add finer-grained levels here for drill-down +``` + +### JSON format (MDL manifest) + +After `wren context build`, the same cube serialises to camelCase: + +```json +{ + "name": "order_metrics", + "baseObject": "orders", + "measures": [ + { "name": "revenue", "expression": "SUM(o_totalprice)", "type": "DOUBLE" } + ], + "dimensions": [ + { "name": "status", "expression": "o_orderstatus", "type": "VARCHAR" } + ], + "timeDimensions": [ + { "name": "created_at", "expression": "o_orderdate", "type": "DATE" } + ], + "hierarchies": { "time_drill": ["created_at"] } +} +``` + +## Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `name` | Yes | Unique cube identifier (used by `wren cube describe`, `cubeQuery.cube`, …) | +| `base_object` | Yes | Name of a defined Model or View; becomes `FROM ` in the generated SQL | +| `measures` | Yes | List of `{ name, expression, type }`. `expression` may reference physical columns or other measure names (derived measure) | +| `dimensions` | No | List of `{ name, expression, type }` used for `GROUP BY` and filters | +| `time_dimensions` | No | List of `{ name, expression, type }`. Granularity is picked at query time, not in the cube definition | +| `hierarchies` | No | Map of `name → [dimension_names]`, for BI drill-down navigation. Levels must reference declared dimensions or time dimensions. | + +## Time granularity + +Supported values at query time: `year`, `quarter`, `month`, `week`, `day`, +`hour`, `minute`. + +When a query specifies a time dimension with a granularity, the translator +emits `DATE_TRUNC(granularity, expr)` in the projection and `GROUP BY`. The +column alias is `__` (e.g., `created_at__month`). An +optional `dateRange: [start, end]` becomes a half-open `[start, end)` `WHERE` +clause. + +## Derived measures + +A measure's `expression` may reference other measures by name: + +```yaml +- name: avg_order_value + expression: "revenue / order_count" +``` + +The translator inlines `revenue` and `order_count` before emitting SQL: + +```text +avg_order_value → (SUM(o_totalprice)) / (COUNT(*)) +``` + +Substitution is longest-prefix-first to avoid partial-token replacement +(e.g., `revenue_2` substitutes before `revenue`). **Only the transitive +closure of measures actually requested by the query is resolved** — a cycle +between unrelated measures elsewhere in the cube does not fail a query that +never references them. + +Expressions containing `$` (Postgres `$1` placeholders or `$$tag$$` +dollar-quoted strings) are preserved literally — the translator does not +treat them as regex capture-group templates. + +## Filter operators + +`cubeQuery.filters` accepts these operators: + +`eq` · `neq` · `in` · `not_in` · `gt` · `gte` · `lt` · `lte` · +`contains` · `starts_with` · `is_null` · `is_not_null` + +`in` / `not_in` take an array value. `is_null` / `is_not_null` take no value. +`contains` / `starts_with` produce `LIKE` patterns. + +## Cube vs. View vs. Model + +| Use case | Use | +|---|---| +| Expose raw rows (optionally with calculated fields) | [Model](./model.md) | +| Name a complex `SELECT` for reuse | [View](./view.md) | +| Predefined aggregation API (measures × dimensions) for agents / BI | **Cube** | + +## CLI + +- `wren cube list` — list every cube in the loaded MDL +- `wren cube describe ` — pretty-print the cube schema +- `wren cube query` — build a CubeQuery (CLI flags or `--from `) and run it +- `wren cube query --sql-only ...` — print the generated SQL without executing + +See the [CLI reference](../../reference/cli.md#wren-cube--pre-aggregation-queries). + +## WASM (browser) + +The same translator is exposed in `@wrenai/wren-core-wasm`: + +```javascript +const cubes = engine.listCubes(); +const rows = await engine.cubeQuery({ + cube: "order_metrics", + measures: ["revenue"], + timeDimensions: [{ dimension: "created_at", granularity: "month" }], +}); +``` + +See the [WASM Agent Guide](https://github.com/Canner/WrenAI/blob/main/core/wren-core-wasm/AGENT_GUIDE.md) +and the [`cube-explorer.html`](https://github.com/Canner/WrenAI/blob/main/core/wren-core-wasm/examples/cube-explorer.html) +demo for an interactive form-driven builder. + +## Validation + +Wren-core validates cubes during `AnalyzedWrenMDL::analyze` — i.e., when the +manifest is loaded into the engine, not just at query time: + +- `base_object` must resolve to a defined Model or View +- Derived measures must not form a cycle within the transitive closure of + requested measures +- Levels in `hierarchies` must reference a declared `dimension` or + `time_dimension` + +The CLI's `wren context validate` also runs structural checks on cube YAML +(unique names, `base_object` exists, hierarchy levels) before the manifest +reaches the engine, so common mistakes surface at edit time. diff --git a/docs/core/guides/modeling/overview.md b/docs/core/guides/modeling/overview.md index 6c6187d6ff..e9ebec728b 100644 --- a/docs/core/guides/modeling/overview.md +++ b/docs/core/guides/modeling/overview.md @@ -76,6 +76,24 @@ Views are useful when the object you want to expose is query-shaped rather than See [View](./view.md). +### Cube + +A **Cube** is a pre-aggregated semantic object: a `baseObject` (a Model or +View), plus declared measures, dimensions, time dimensions, and optional +hierarchies. + +Use a cube when you need to: + +- expose pre-defined aggregations (e.g., total revenue by month) +- give AI agents a structured aggregation API (no hand-written `GROUP BY`) +- define drill-down hierarchies (year → quarter → month) for BI dashboards +- share business metrics across CLI, browser (WASM), and downstream consumers + +Cubes complement models: a model exposes the rows; a cube exposes the metrics +defined on top of those rows. + +See [Cube](./cube.md). + ### Memory The **Memory** layer is a LanceDB-backed semantic index that gives AI agents targeted schema context and few-shot query examples — without sending the entire schema in every prompt. @@ -98,6 +116,7 @@ Use this rule of thumb: - Use a **Relationship** to define how models join to each other. - Use a **Calculated Field** to define reusable expression logic inside a model. - Use a **View** to publish a reusable query result. +- Use a **Cube** to publish a structured aggregation API (measures × dimensions). - Use **Memory** to give AI agents targeted context and learning from past queries. ## Why this matters diff --git a/docs/core/reference/cli.md b/docs/core/reference/cli.md index fb58cb219f..43301022c2 100644 --- a/docs/core/reference/cli.md +++ b/docs/core/reference/cli.md @@ -200,3 +200,72 @@ Drop all memory tables and start fresh. wren memory reset # prompts for confirmation wren memory reset --force # skip confirmation ``` + +--- + +## `wren cube` — Pre-aggregation Queries + +For aggregation queries where the MDL defines cubes, use `wren cube` instead +of writing raw SQL. The translator produces correct `GROUP BY`, `DATE_TRUNC`, +and `WHERE` clauses from a structured input. + +### `wren cube list` + +List all cubes in the loaded MDL with their measures and dimensions. + +```bash +wren cube list +``` + +### `wren cube describe ` + +Pretty-print the full cube schema as JSON: `baseObject`, measures (with +expressions), dimensions, time dimensions, hierarchies. + +```bash +wren cube describe order_metrics +``` + +### `wren cube query` + +Build a CubeQuery and translate it to SQL via wren-core, then execute through +the same path as `wren --sql`. Two input modes: + +**CLI flags:** + +```bash +wren cube query \ + --cube order_metrics \ + --measures revenue,order_count \ + --dimensions status \ + --time-dimension "created_at:month:2024-01-01,2025-01-01" \ + --filter "status:eq:completed" \ + --limit 100 +``` + +**JSON input** (`--from `): + +```bash +cat query.json | wren cube query --from - +``` + +| Flag | Description | +|------|-------------| +| `--cube` | Cube name (required unless using `--from`) | +| `--measures` | Comma-separated measure names (required unless using `--from`) | +| `--dimensions` | Comma-separated dimension names | +| `--time-dimension` | `:[:start,end]` — one time dimension with optional date range | +| `--filter` | Repeatable. `:[:value]`. For `in` / `not_in`, value is comma-separated. | +| `--limit` / `--offset` | Pagination | +| `--from ` | Load CubeQuery as JSON from a file or stdin | +| `--sql-only` | Print the generated SQL and exit without executing | +| `--mdl` | Path to MDL JSON (defaults to `/target/mdl.json`) | +| `--output` | `table` (default), `json`, `csv` | + +**Supported granularities:** `year`, `quarter`, `month`, `week`, `day`, `hour`, `minute`. + +**Supported filter operators:** `eq`, `neq`, `in`, `not_in`, `gt`, `gte`, `lt`, +`lte`, `contains`, `starts_with`, `is_null`, `is_not_null`. + +See the [Cube guide](../guides/modeling/cube.md) for YAML structure and +validation rules. diff --git a/skills/wren-generate-mdl/SKILL.md b/skills/wren-generate-mdl/SKILL.md index 12c3b1e3fd..2812c1a9f0 100644 --- a/skills/wren-generate-mdl/SKILL.md +++ b/skills/wren-generate-mdl/SKILL.md @@ -186,12 +186,19 @@ This creates: ```text project/ ├── wren_project.yml -├── models/ -├── views/ +├── models/ # business-facing tables/models +├── views/ # named SQL statements +├── cubes/ # pre-aggregation cubes (measures + dimensions) ├── relationships.yml └── instructions.md ``` +> **When to define cubes:** If the user asks aggregation questions like +> "revenue by month" or "top customers", define cubes alongside models — +> they give agents a structured query API instead of forcing them to +> hand-write `GROUP BY` / `DATE_TRUNC` SQL. See the +> [Cube guide](https://github.com/Canner/WrenAI/blob/main/docs/core/guides/modeling/cube.md). + > **IMPORTANT: `catalog` and `schema` in `wren_project.yml`** > > These are Wren Engine's internal namespace — they are NOT the database's diff --git a/skills/wren-usage/SKILL.md b/skills/wren-usage/SKILL.md index e56f8f95fe..c91483b78e 100644 --- a/skills/wren-usage/SKILL.md +++ b/skills/wren-usage/SKILL.md @@ -4,7 +4,7 @@ description: "Wren Engine CLI workflow guide for AI agents. Answer data question license: Apache-2.0 metadata: author: wren-engine - version: "2.2" + version: "2.3" --- # Wren Engine CLI — Agent Workflow Guide @@ -304,6 +304,7 @@ wren --sql "SELECT * FROM LIMIT 1" ```text Get data back → wren --sql "..." +Aggregation across dims → wren cube query --cube --measures (if cube defined) See translated SQL only → wren dry-plan --sql "..." (accepts -d if no active profile) Validate against DB → wren dry-run --sql "..." Schema context → wren memory fetch -q "..." @@ -320,6 +321,97 @@ Switch profile → wren profile switch --- +## Cube Query Workflow + +When the user asks an aggregation question (e.g., "total revenue by month", +"top customers"), check if the MDL defines cubes before writing raw SQL. + +### Step 1: Discover cubes + +```bash +wren cube list +``` + +If cubes exist and cover the user's question, prefer cube query over raw SQL. +Lower error rate, especially for small / local models — agents don't have to +hand-write GROUP BY / DATE_TRUNC. + +### Step 2: Inspect cube structure + +```bash +wren cube describe +``` + +Shows the cube's baseObject, measures (with expressions), dimensions, +time dimensions, and hierarchies. + +### Step 3: Match user's question to cube measures + dimensions + +| User phrase | Maps to | +|---|---| +| "total revenue" | `--measures revenue` | +| "by month" | `--time-dimension "created_at:month"` | +| "in 2024" | `--time-dimension "created_at:month:2024-01-01,2025-01-01"` | +| "for completed orders" | `--filter "status:eq:completed"` | +| "top N customers" | `--dimensions customer --limit N` | + +### Step 4: Execute via CLI flags OR JSON input + +CLI flags: + +```bash +wren cube query \ + --cube order_metrics \ + --measures revenue,order_count \ + --time-dimension "created_at:month:2024-01-01,2025-01-01" \ + --filter "status:eq:completed" \ + --limit 100 +``` + +JSON input (good for agent-generated structured queries): + +```bash +echo '{"cube":"order_metrics","measures":["revenue"]}' | wren cube query --from - +``` + +Add `--sql-only` to print the generated SQL without executing — useful for +verification before paying for execution on a remote warehouse. + +### Step 5: Error recovery + +| Error | Action | +|---|---| +| `Unknown measure 'X'` | `wren cube describe ` for available measures | +| `Unknown dimension 'X'` | `wren cube describe ` for available dimensions | +| `Cube 'X' not found` | `wren cube list` | +| `Circular dependency detected` | Derived measure references itself — inspect the cube YAML | + +### When NOT to use cube query + +Fall back to `wren --sql` when: + +- Custom JOINs across multiple models +- Window functions, CTEs, or subqueries +- Queries with no aggregation +- No cubes defined in the MDL + +--- + +## Aggregation decision tree + +```text +User question → Is it an aggregation question? + (SUM, COUNT, AVG, GROUP BY, "by month", "per customer", ...) + ├── Yes → Are cubes defined? (`wren cube list` once at start of session) + │ ├── Yes → Does a cube cover the question? (`wren cube describe`) + │ │ ├── Yes → Use `wren cube query` (preferred — lower error rate) + │ │ └── No → Write raw SQL with `wren --sql` + │ └── No → Write raw SQL with `wren --sql` + └── No → Write raw SQL with `wren --sql` (look for memory recall first) +``` + +--- + ## Things to avoid - Do not guess model or column names — check context first diff --git a/skills/wren-usage/references/memory.md b/skills/wren-usage/references/memory.md index 551cfe38d8..34d8bdd376 100644 --- a/skills/wren-usage/references/memory.md +++ b/skills/wren-usage/references/memory.md @@ -23,6 +23,24 @@ Override with `--threshold`: wren memory fetch -q "revenue" --threshold 50000 # raise for larger context windows ``` +### Cube schema items + +When the MDL defines cubes, `wren memory index` emits these additional schema items: + +- `cube:` — cube overview (base object, measure list, dimension list) +- `measure:.` — each measure (with expression and type) +- `cube_dimension:.` — each dimension +- `time_dimension:.` — each time dimension + +These items are reachable via `wren memory fetch ""`. For aggregation +questions like "revenue by month", cube schema items typically rank higher than +model columns because they match the aggregation intent more directly — then +the agent should follow up with `wren cube describe ` and `wren cube query` +rather than hand-writing `GROUP BY` SQL. + +`wren memory describe` also adds a cube section that lists each cube's measures, +dimensions, time dimensions, and hierarchies in markdown. + --- ## Indexing: `wren memory index` diff --git a/skills/wren-usage/references/wren-sql.md b/skills/wren-usage/references/wren-sql.md index 69865ab692..d322d283f6 100644 --- a/skills/wren-usage/references/wren-sql.md +++ b/skills/wren-usage/references/wren-sql.md @@ -106,3 +106,51 @@ If the rewriter detects no model references in your SQL (e.g. `SELECT 1` or quer - Queries that don't reference any MDL model still work - The fallback path does NOT use CTE injection — it transforms the whole query at once - If you expect model expansion but get none, check that your FROM clause uses model names from the MDL + +--- + +## Cube query SQL generation + +`wren cube query` doesn't execute SQL directly — it produces SQL from a +structured CubeQuery input and hands it to the engine. Inspecting +`--sql-only` output is how an agent reverse-engineers cube expansion logic. + +### Generated SQL pattern + +```sql +SELECT DATE_TRUNC('month', o_orderdate) AS created_at__month, + o_orderstatus AS status, + SUM(o_totalprice) AS revenue, + COUNT(*) AS order_count +FROM orders -- ← cube.baseObject +WHERE o_orderdate >= '2024-01-01' + AND o_orderdate < '2025-01-01' -- ← dateRange (end exclusive) + AND o_orderstatus = 'completed' -- ← filter +GROUP BY 1, 2 -- ← GROUP BY ordinals for all dims +ORDER BY 1 +LIMIT 100 +``` + +### Key points + +- **`FROM` is the cube's `baseObject`** — wren-core then resolves it to the + underlying model/view, so all existing model rewrite rules still apply. +- **Time dimensions use `DATE_TRUNC(granularity, expr)`**; the column alias + is `__` (e.g., `created_at__month`). +- **Date range is `[start, end)` half-open** — the `end` day is excluded. +- **Derived measures inline-expand**: `avg_order_value = revenue / order_count` + becomes `(SUM(o_totalprice)) / (COUNT(*))`. Longest dependency name + substitutes first to avoid partial-token bugs (e.g., `revenue_2` before + `revenue`). +- **Expressions containing `$` are safe**: Postgres `$1` parameter placeholders + and `$$tag$$` dollar-quoted literals are kept literal, not misread as + regex capture-group templates. + +### Diagnosing cube SQL errors + +1. `wren cube query --sql-only ...` to inspect the generated SQL. +2. If the SQL looks reasonable, run `wren cube query ...` (drop `--sql-only`). +3. If the execution error is "unknown column / table", the cube YAML's + `expression` is likely wrong — not the translator. +4. If translation itself fails (e.g., cyclic measure), the error is raised + before execution and names the offending measure. From 8c205c55ac670614adb40e23d74db21e669774a2 Mon Sep 17 00:00:00 2001 From: Jax Liu Date: Thu, 14 May 2026 18:45:21 +0800 Subject: [PATCH 2/3] chore(skills): bump wren-usage to 2.3 in versions.json + index.json Match the SKILL.md version bump that landed in the previous commit so the parity check passes. Co-Authored-By: Claude Opus 4.7 (1M context) --- skills/index.json | 2 +- skills/versions.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/skills/index.json b/skills/index.json index 5654b9c551..b7662f27a3 100644 --- a/skills/index.json +++ b/skills/index.json @@ -65,7 +65,7 @@ }, { "name": "wren-usage", - "version": "2.2", + "version": "2.3", "description": "Wren Engine CLI workflow guide for AI agents. Triggers on data questions, reports, metrics, revenue, trends, 'how many', 'show me', 'top N', 'compare', 'breakdown'. Answer data questions end-to-end using the wren CLI.", "tags": [ "wren", diff --git a/skills/versions.json b/skills/versions.json index df6251edba..04885f7dd6 100644 --- a/skills/versions.json +++ b/skills/versions.json @@ -2,5 +2,5 @@ "wren-dlt-connector": "1.0", "wren-generate-mdl": "2.2", "wren-onboarding": "2.1", - "wren-usage": "2.2" + "wren-usage": "2.3" } From 95a11fd8a6d0aec44735ac215b9f022a745cf61f Mon Sep 17 00:00:00 2001 From: Jax Liu Date: Thu, 14 May 2026 18:54:51 +0800 Subject: [PATCH 3/3] docs(wren): fix broken cube CLI reference anchor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The heading is `## \`wren cube\` — Pre-aggregation Queries`, so GitHub emits anchor `#wren-cube--pre-aggregation-queries`, not the placeholder `#cube-commands` the link previously used. quickstart.md and cube.md were already correct. Co-Authored-By: Claude Opus 4.7 (1M context) --- core/wren/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/wren/README.md b/core/wren/README.md index aa944bbb86..fd13d863f7 100644 --- a/core/wren/README.md +++ b/core/wren/README.md @@ -116,7 +116,7 @@ wren cube query --cube order_metrics --measures revenue --time-dimension "create The translator produces `DATE_TRUNC` / `GROUP BY` / `WHERE` clauses for you and runs them through the same engine path as `wren --sql`. See the [Cube guide](../../docs/core/guides/modeling/cube.md) for full YAML structure -and the [CLI reference](../../docs/core/reference/cli.md#cube-commands) for all +and the [CLI reference](../../docs/core/reference/cli.md#wren-cube--pre-aggregation-queries) for all flags. **5. (Optional) Configure security policy** — create `~/.wren/config.json`: