About cubes
cubes is a skill for managing semantic-model cube definitions through RevOS, for people maintaining analytical data models. It covers reading and writing definitions, checking compilation and queries, and restoring prior state when a change breaks the model.
Key features
- 01Read and maintain cube definitions
- 02Inspect compiled model metadata
- 03Verify compilation and SQL queries
- 04Check dependencies before renaming or deleting
- 05Restore definitions after failed writes
Use cases
- 01Review a cube's tables, dimensions, and measures
- 02Add or change model relationships
- 03Check that cube changes are queryable
- 04Find references before deleting a cube
MCP support
It accesses the `cubes` resource through RevOS MCP server generic tools to read, create, update, and delete definitions, and query the compiled model.
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ revosai/ skills --skill cubesAfter installing, type/cubesin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
evals/evals.jsonreferences/create.mddefinition.mddelete.mdedit.mdDetails
From the project READMECubes
A cube is one stored definition in the org's semantic model: which warehouse
table it reads (sql_table), the dimensions you group and filter by,
the measures you aggregate, and the joins to other cubes. Tables,
segments, and every semantic-model query are built on top of these.
You reach them through the RevOS MCP server's generic tools on the cubes
resource:
| Call | What it does |
|---|---|
api_read { "resource": "cubes", "params": { "fields": "id,name,updatedAt" } } | list the stored definitions |
api_read { "resource": "cubes", "id": "<cube id>" } | one stored definition, under definition |
api_read { "resource": "cubes", "method": "meta", "params": { "filter": "name == \"crm_deals\"" } } | the compiled cube as the org can query it |
api_write { "resource": "cubes", "data": { "name", "definition" } } | create |
api_write { "resource": "cubes", "id": "<cube id>", "data": { "definition" } } | update |
api_delete { "resource": "cubes", "id": "<cube id>" } | delete |
The record always goes under data. A body under any other key may be
ignored without an error. api_details({ resource: "cubes", operation: "create" }) is the authority on the definition's JSON schema.
The one thing to keep in mind
The server checks a definition's shape, not whether it compiles, and Cube
compiles all of the org's cubes together. Unknown dimension, measure and
join keys are rejected with a named error, but unknown keys at the top of the
definition (sqlTable for sql_table) are silently dropped — which can leave
a cube with no source. Always send definition.name too: it's optional on
create, but Cube compiles by it. A definition that doesn't compile doesn't
fail on save.
It fails the whole org's semantic model: every table, segment, and query
errors until someone fixes it. Common causes are a join to a cube that
doesn't exist, a ${…} reference to a member that isn't there, or a removed
dimension that a table column still uses. A wrong column name or bad SQL is
quieter: the model compiles, and only queries touching that member fail.
So every write follows the same loop:
- Keep the before-state. For an edit, hold the full current
definitionyou just read. For a create, remember the new id. - Write.
- Verify at once with
metafiltered to the cube's name. An error there means the org's model no longer compiles. Restore immediately: write the saved definition back, or delete the cube you just created. Then tell the user what happened, and don't keep editing on a broken model. The error itself says only "The RevOS API failed with status 500" — the compile error isn't passed through, so don't promise the user a cause; point them to the logs or Cube Playground for it. Ifmetastill shows the old version, wait a few seconds and read again; Cube polls for changes. - Prove the SQL with one small query over the members you added or
changed:
api_read { "resource": "cubes", "method": "query", "body": { "query": { "dimensions": ["crm_deals.stage"], "measures": ["crm_deals.count"], "limit": 3 } } }. An error here names the bad column or expression. Fix it the same way.
Writes need the Developer (or Admin) role. A 403 means the connected user doesn't have it, so say so rather than retrying.
Before the first write: two checks
What's generated, not stored? meta lists the stored cubes plus what
RevOS generates: a cube per table with stored columns or scores
(model_stream_…___local, titled [Table] <name>), one per static segment
(segment_…, [Segment] <name>), and a view per table (model_…). These
also add joins onto stored cubes, so a cube's joins in meta can list
joins its stored definition doesn't have. An org with no stored cubes still
shows the generated ones; creating a cube adds to them and removes nothing.
Are the cubes managed as code? Some orgs ship cubes from a repo with the
RevOS CLI (revos apply). An edit made here is overwritten on their next
apply. If the user mentions a repo or the CLI, point them there instead.
Reading
- What's defined, and how: list with
fields: "id,name,updatedAt", thengetby id for the fulldefinition. The list'sfilteris CEL onname(name == "crm_deals",name.startsWith("hubspot_")). - What's actually queryable:
meta. It differs from the stored list:- It is compiled. Members are fully qualified, such as
crm_deals.amount, and use camelCase keys. - It adds the cubes RevOS generates itself, which you never write:
- a cube per table that has stored columns or scores, named
model_stream_…___local(a table that only reads cubes has none); - a cube per static segment, named
segment_…; - a view per table.
- a cube per table that has stored columns or scores, named
- It is compiled. Members are fully qualified, such as
When the user asks how a cube is defined, show the relevant part of the stored definition: the table, the dimensions with their types, the measures, and the joins. Explain it in plain words. Don't dump the JSON. To answer questions about the data, switch to semantic-model.
Who depends on a cube
Before you rename or remove anything, or delete a cube, find its users. Each reference to the old name or member breaks:
- Other cubes: a
joinskey equal to this cube's name, or${name.…}in any join, dimension, or measure SQL. Get each stored definition and search it. Joins are declared on either side. - Tables: list them with
api_read { "resource": "tables", "params": { "fields": "id,name,streams,objectsColumns" } }. Each table has:streams[].id(a cube name) andstreams[].joinPath(dotted cube names);objectsColumns[]: eachexternal: trueone hasstreamId+pathpointing at a cube's dimension, or its measure whenmeasure: true. A stream withoutjoinPathis joined as<root>.<id>.
- Segments: list them, then
geteach by id. Each hascubes[].joinPathand themembers in itsfilter. A STATIC one also joins itssegment_…cube oncubes[0]'sprimaryKeyDimension. - Dashboard cards: list them with
api_read { "resource": "dashboard-cards", "params": { "fields": "id,dashboardId,title,measure,breakdown,filter,joinPaths", "pageSize": 200 } }. Each names members inmeasure,breakdownand itsfilter, and cubes injoinPaths. Cards aren't checked when the model changes: a broken one doesn't stop the model compiling, it just shows as unavailable on the dashboard — still worth telling the user.
Report what you found to the user before acting: "crm_deals is used by the Deals table (7 columns), 2 segments and 3 dashboard cards".
Creating, editing, deleting
Each has its own reference. Read the one you need before writing:
- New cube: references/create.md
- Change a cube (add or fix members, joins, rename): references/edit.md
- Delete a cube: references/delete.md
- Definition syntax (dimensions, measures, joins, SQL references): references/definition.md
Reporting back
After a write, tell the user in two or three sentences:
- what changed, in their terms ("added Amount as a sum measure on Deals");
- that
metacompiled and a test query ran; - any judgment call you made, such as a join's relationship or a dimension's type.
If you had to restore, say so plainly, along with the error that caused it.