A common ask from teams evaluating Sigma is migrating their ThoughtSpot footprint — usually to take advantage of all the amazing things Sigma offers. The conversion itself can be a blocker — and the part this QuickStart automates.

The usual ThoughtSpot-to-Sigma migration loop is rebuild-the-worksheet-by-hand, rewrite every search query and aggregate formula as a Sigma formula, recreate each Liveboard visualization, line the layout up against the source, then eyeball the numbers and hope nothing drifted in the translation. Done on a single Liveboard it's tedious. Across an entire org with dozens of Liveboards reading from a shared worksheet, it's the reason migration projects slip.

This QuickStart walks through a Claude Code skill called thoughtspot-to-sigma that automates the loop.

Point it at a ThoughtSpot worksheet (model); it exports the TML for the model and every Liveboard that reads it, translates the aggregate formulas and search-query filters into a Sigma data model and matching workbooks, mirrors each Liveboard's layout onto Sigma's grid, and runs a verification pass that compares every chart's numbers to ThoughtSpot's own searchdata API. It surfaces a punch list of anything it couldn't auto-translate — including chart kinds Sigma doesn't natively support (funnel, waterfall, treemap, heat-map, sankey all fall back to bar charts) — instead of silently producing a broken workbook.

For the demonstration, we'll run the skill end-to-end against a six-table retail-star ThoughtSpot model called Retail Analytics, migrating one of the Liveboards (Sales Overview (TS)) that reads from it.

You'll see the TML each phase produces, the converter's breakdown of how each search query mapped to a Sigma formula, the parity report against the live warehouse, and the resulting Sigma data model and workbook landed in your org — along with the gap list of items to hand-polish.

What else this enables

A pure lift-and-shift is the floor, not the ceiling. The same skill family supports three follow-on moves that turn a migration into an upgrade:

Target Audience

Sigma SEs, technical CSMs, and migration partners running ThoughtSpot-to-Sigma conversions — or scoping a batch migration with the companion thoughtspot-assessment skill.

Prerequisites

Sigma Free Trial

Footer

thoughtspot-to-sigma is one of two skills that ship together as a single repo (cloned in the next section). Most of this QuickStart focuses on the converter — but knowing where the assessment skill fits saves dead ends later when scoping a batch migration.

Skill

Role

When to reach for it

thoughtspot-assessment

Scoping

Auditing a ThoughtSpot org before committing to a conversion plan. Emits a per-Liveboard complexity readout, a ranked migration shortlist (value/cost derived from TS: BI Server usage), a chart-type coverage scan, and a cluster plan that thoughtspot-to-sigma can consume in batch mode.

thoughtspot-to-sigma

Conversion

The subject of this QuickStart. Converts a single worksheet plus its Liveboards (or a batch via cluster plan) to a Sigma data model and matching workbooks with verified data parity.

Here's how the two skills connect in a full migration — thoughtspot-assessment hands the converter a ranked shortlist and cluster plan, and thoughtspot-to-sigma produces the Sigma workbooks with a verified parity report:

Which skill for your situation

Not every migration needs both skills. Use the table below to map your scenario to the smallest set that fits.

In this QuickStart we're in the first row — one Liveboard on an Embrace model whose data we'll land in Snowflake so the Sigma connection can read it — then run thoughtspot-to-sigma.

Your situation

Skill(s) to use

1 Liveboard, worksheet already reads from your warehouse

thoughtspot-to-sigma

1 Liveboard, Falcon-only worksheet with no warehouse copy of the data

Land the data in your warehouse first (covered in Prepare the Demo Data), then thoughtspot-to-sigma

10+ Liveboards (any data source)

thoughtspot-assessmentthoughtspot-to-sigma in batch mode

Auditing ThoughtSpot sprawl without converting yet

thoughtspot-assessment only

Footer

First we need to clone the skill's GitHub repository, then run the setup scripts that capture your Sigma and ThoughtSpot credentials.

The two skills live in sigmacomputing/quickstarts-public under thoughtspot-migration-skills/.

From a terminal, run each command below one at a time so you can confirm each step before moving on.

Step 1: Create a local folder for the clone
We'll clone into this folder in the next step.

mkdir -p ~/quickstarts-public

Step 2: Move into the new folder so the next command runs in the right working directory.

cd ~/quickstarts-public

Step 3: Clone the repo without pulling any files yet
The --sparse flag tells Git you'll choose which folders to fill in next. The trailing . clones into the current folder.

git clone --filter=blob:none --sparse https://github.com/sigmacomputing/quickstarts-public.git .

Step 4: Fill in only the thoughtspot-migration-skills folder
Every other QuickStart asset in the repo stays empty on disk.

git sparse-checkout set thoughtspot-migration-skills

Step 5: Symlink thoughtspot-to-sigma into the Claude skills folder
This lets Claude Code invoke thoughtspot-to-sigma as a skill.

ln -s ~/quickstarts-public/thoughtspot-migration-skills/thoughtspot-to-sigma ~/.claude/skills/thoughtspot-to-sigma

Step 6: Symlink thoughtspot-assessment
Used to scope a ThoughtSpot org before conversion.

ln -s ~/quickstarts-public/thoughtspot-migration-skills/thoughtspot-assessment ~/.claude/skills/thoughtspot-assessment

Steps 5 and 6 should return with no error.

divider

Step 7: Install the one Python dependency the skill uses.
The skill's helpers read ThoughtSpot's TML (ThoughtSpot Modeling Language) with PyYAML. Everything else the skill needs is in Python's standard library.

python3 -m pip install pyyaml

Step 8: Capture your Sigma API credentials.
This script prompts for SIGMA_BASE_URL, SIGMA_CLIENT_ID, and SIGMA_CLIENT_SECRET and writes them into Claude's settings.

Run once per machine.

If you don't already have credentials, see Configure API credentials in Sigma — the skill needs API access credentials, not embed.

ruby ~/.claude/skills/thoughtspot-to-sigma/scripts/setup.rb

Step 9: Authenticate with ThoughtSpot.
ThoughtSpot's REST v2 API uses a bearer token.

On an SSO trial without a local password, the quickest way to get one is to open the token endpoint directly in the browser tab where you're already signed in to ThoughtSpot:

https://<your-tenant>.thoughtspot.cloud/api/rest/2.0/auth/session/token

The browser returns a small JSON payload:

Copy the token value (the long string inside the quotes), then paste it into the code below to export both your tenant URL and the token in your terminal:

export TS_HOST="https://<your-tenant>.thoughtspot.cloud"
export TS_TOKEN="<paste-the-token-here>"

divider

Step 10: Verify the install.
This lists every model and Liveboard visible to your token — confirms both ThoughtSpot authentication and the skill's installation worked.

python3 ~/.claude/skills/thoughtspot-to-sigma/scripts/ts_discover.py

You should see your tenant's models and Liveboards listed:

divider

Step 11: Verify Claude Code can invoke the skill.
Type claude in your terminal to start Claude Code, then invoke the skill:

claude
/thoughtspot-to-sigma

Claude should start reading the reference files and ask what worksheet you want to convert.

Pause at this response:

Before going any further, we need to prepare the data the worksheet uses. We'll hand the worksheet, Liveboard, and warehouse details to Claude all at once via a single prompt in Run the Conversion.

Footer

The ThoughtSpot model we're migrating — Retail Analytics — is an Embrace model, meaning it reads directly from a warehouse rather than from ThoughtSpot's in-memory Falcon engine. For the migration to land in Sigma cleanly, the same six warehouse tables Retail Analytics reads from need to exist in a connection your Sigma org can reach.

The schema is a classic retail star — one fact (ORDER_FACT) joined LEFT_OUTER to five dimension tables (CUSTOMER_DIM, PRODUCT_DIM, STORE_DIM, DATE_DIM, PROMO_DIM). Approximate row counts: 681 / 25 / 25 / 15 / 1,096 / 23.

Data prep has two halves:

  1. ThoughtSpot side — nothing to do here for this QuickStart. We've already exported the six tables from the source warehouse and hosted them as CSVs in Amazon S3. The Snowflake COPY INTO statements below read from S3 directly — no local download needed.
  2. Sigma side (this section) — the same data needs to live in a Snowflake schema your Sigma connection can read. We'll create one.
USE ROLE ACCOUNTADMIN;
USE WAREHOUSE COMPUTE_WH;

CREATE DATABASE IF NOT EXISTS QUICKSTARTS;
CREATE SCHEMA  IF NOT EXISTS QUICKSTARTS.TS_RETAIL_ANALYTICS;
USE SCHEMA QUICKSTARTS.TS_RETAIL_ANALYTICS;

CREATE OR REPLACE FILE FORMAT csv_format
  TYPE = CSV
  FIELD_DELIMITER = ','
  SKIP_HEADER = 1
  FIELD_OPTIONALLY_ENCLOSED_BY = '"'
  NULL_IF = ('', 'NULL')
  EMPTY_FIELD_AS_NULL = TRUE;

CREATE OR REPLACE STAGE ts_retail_stage
  URL = 's3://sigma-quickstarts-main/thoughtspot/'
  FILE_FORMAT = csv_format;

-- Fact: ORDER_FACT (681 rows, joins to all 5 dims via *_KEY columns).
CREATE OR REPLACE TABLE ORDER_FACT (
  ORDER_ID           VARCHAR,
  ORDER_LINE         NUMBER(38,0),
  CUSTOMER_KEY       NUMBER(38,0),
  PRODUCT_KEY        NUMBER(38,0),
  ORDER_STORE_KEY    NUMBER(38,0),
  SHIP_STORE_KEY     NUMBER(38,0),
  PROMO_KEY          NUMBER(38,0),
  ORDER_DATE_KEY     NUMBER(38,0),
  SHIP_DATE_KEY      NUMBER(38,0),
  RETURN_DATE_KEY    NUMBER(38,0),
  ORDER_CHANNEL      VARCHAR,
  SHIP_METHOD        VARCHAR,
  ORDER_STATUS       VARCHAR,
  QUANTITY_ORDERED   NUMBER(38,0),
  QUANTITY_RETURNED  NUMBER(38,0),
  UNIT_PRICE         NUMBER(38,2),
  UNIT_COST          NUMBER(38,2),
  DISCOUNT_AMOUNT    NUMBER(38,2),
  SHIPPING_AMOUNT    NUMBER(38,2),
  TAX_AMOUNT         NUMBER(38,2),
  GROSS_REVENUE      NUMBER(38,2),
  NET_REVENUE        NUMBER(38,2),
  GROSS_PROFIT       NUMBER(38,2),
  NET_PROFIT         NUMBER(38,2),
  IS_FIRST_ORDER     NUMBER(1,0),
  IS_RETURNED        NUMBER(1,0),
  IS_CANCELLED       NUMBER(1,0),
  DAYS_TO_SHIP       NUMBER(38,0)
);

CREATE OR REPLACE TABLE CUSTOMER_DIM (
  CUSTOMER_KEY          NUMBER(38,0),
  CUSTOMER_ID           VARCHAR,
  FIRST_NAME            VARCHAR,
  LAST_NAME             VARCHAR,
  EMAIL                 VARCHAR,
  PHONE                 VARCHAR,
  CITY                  VARCHAR,
  STATE                 VARCHAR,
  ZIP_CODE              VARCHAR,
  REGION                VARCHAR,
  CUSTOMER_SEGMENT      VARCHAR,
  LOYALTY_TIER          VARCHAR,
  ACQUISITION_CHANNEL   VARCHAR,
  FIRST_ORDER_DATE      DATE,
  IS_ACTIVE             NUMBER(1,0),
  IS_EMAIL_OPT_IN       NUMBER(1,0),
  LIFETIME_ORDER_COUNT  NUMBER(38,0),
  LIFETIME_REVENUE      NUMBER(38,2)
);

CREATE OR REPLACE TABLE PRODUCT_DIM (
  PRODUCT_KEY         NUMBER(38,0),
  PRODUCT_ID          VARCHAR,
  PRODUCT_NAME        VARCHAR,
  CATEGORY            VARCHAR,
  SUBCATEGORY         VARCHAR,
  BRAND               VARCHAR,
  UNIT_COST           NUMBER(38,2),
  UNIT_PRICE          NUMBER(38,2),
  WEIGHT_LBS          NUMBER(38,2),
  IS_ACTIVE           NUMBER(1,0),
  IS_PRIVATE_LABEL    NUMBER(1,0),
  IS_SEASONAL         NUMBER(1,0),
  LAUNCH_DATE         DATE,
  DISCONTINUE_DATE    DATE,
  "Product_Key/Name"  VARCHAR
);

CREATE OR REPLACE TABLE STORE_DIM (
  STORE_KEY          NUMBER(38,0),
  STORE_ID           VARCHAR,
  STORE_NAME         VARCHAR,
  STORE_TYPE         VARCHAR,
  CITY               VARCHAR,
  STATE              VARCHAR,
  REGION             VARCHAR,
  DISTRICT           VARCHAR,
  SQUARE_FOOTAGE     NUMBER(38,0),
  OPEN_DATE          DATE,
  CLOSE_DATE         DATE,
  IS_ACTIVE          NUMBER(1,0),
  HAS_CAFE           NUMBER(1,0),
  HAS_CURBSIDE       NUMBER(1,0),
  MANAGER_NAME       VARCHAR,
  STORE_PHONE        VARCHAR,
  ANNUAL_LEASE_COST  NUMBER(38,2)
);

CREATE OR REPLACE TABLE DATE_DIM (
  DATE_KEY        NUMBER(38,0),
  FULL_DATE       DATE,
  DAY_OF_WEEK     VARCHAR,
  DAY_OF_MONTH    NUMBER(38,0),
  WEEK_OF_YEAR    NUMBER(38,0),
  MONTH_NUMBER    NUMBER(38,0),
  MONTH_NAME      VARCHAR,
  QUARTER         NUMBER(38,0),
  "YEAR"          NUMBER(38,0),
  IS_WEEKEND      NUMBER(1,0),
  IS_HOLIDAY      NUMBER(1,0),
  FISCAL_PERIOD   VARCHAR
);

CREATE OR REPLACE TABLE PROMO_DIM (
  PROMO_KEY          NUMBER(38,0),
  PROMO_ID           VARCHAR,
  PROMO_NAME         VARCHAR,
  PROMO_TYPE         VARCHAR,
  CHANNEL            VARCHAR,
  DISCOUNT_PCT       NUMBER(38,2),
  START_DATE         DATE,
  END_DATE           DATE,
  MIN_ORDER_AMOUNT   NUMBER(38,2),
  IS_STACKABLE       NUMBER(1,0),
  TARGET_SEGMENT     VARCHAR,
  PROMO_COST         NUMBER(38,2)
);

-- Load each CSV from S3.
COPY INTO ORDER_FACT    FROM @ts_retail_stage/ORDER_FACT.csv    ON_ERROR = ABORT_STATEMENT;
COPY INTO CUSTOMER_DIM  FROM @ts_retail_stage/CUSTOMER_DIM.csv  ON_ERROR = ABORT_STATEMENT;
COPY INTO PRODUCT_DIM   FROM @ts_retail_stage/PRODUCT_DIM.csv   ON_ERROR = ABORT_STATEMENT;
COPY INTO STORE_DIM     FROM @ts_retail_stage/STORE_DIM.csv     ON_ERROR = ABORT_STATEMENT;
COPY INTO DATE_DIM      FROM @ts_retail_stage/DATE_DIM.csv      ON_ERROR = ABORT_STATEMENT;
COPY INTO PROMO_DIM     FROM @ts_retail_stage/PROMO_DIM.csv     ON_ERROR = ABORT_STATEMENT;

-- Grant Sigma's service role visibility on the new schema and its tables.
GRANT USAGE  ON DATABASE QUICKSTARTS                                    TO ROLE SIGMA_SERVICE_ROLE;
GRANT USAGE  ON SCHEMA   QUICKSTARTS.TS_RETAIL_ANALYTICS                TO ROLE SIGMA_SERVICE_ROLE;
GRANT SELECT ON ALL    TABLES IN SCHEMA QUICKSTARTS.TS_RETAIL_ANALYTICS TO ROLE SIGMA_SERVICE_ROLE;
GRANT SELECT ON FUTURE TABLES IN SCHEMA QUICKSTARTS.TS_RETAIL_ANALYTICS TO ROLE SIGMA_SERVICE_ROLE;

-- Sanity-check row counts. Expected: 681 / 25 / 25 / 15 / 1096 / 23.
SELECT 'ORDER_FACT'   AS TABLE_NAME, COUNT(*) AS ROW_COUNT FROM ORDER_FACT   UNION ALL
SELECT 'CUSTOMER_DIM', COUNT(*) FROM CUSTOMER_DIM UNION ALL
SELECT 'PRODUCT_DIM',  COUNT(*) FROM PRODUCT_DIM  UNION ALL
SELECT 'STORE_DIM',    COUNT(*) FROM STORE_DIM    UNION ALL
SELECT 'DATE_DIM',     COUNT(*) FROM DATE_DIM     UNION ALL
SELECT 'PROMO_DIM',    COUNT(*) FROM PROMO_DIM;

-- Verify the parity baseline ($108,797.85 Net Revenue across all orders).
SELECT TO_CHAR(SUM(NET_REVENUE), '$999,999,999.99') AS TOTAL_NET_REVENUE
FROM ORDER_FACT;

If the load completes cleanly, the row-count check returns 681 / 25 / 25 / 15 / 1096 / 23 and the Net Revenue check returns $108,797.85. Any mismatch means either a COPY partial-load error (check Snowflake's load history) or a different S3 file than expected.

Footer

The converter needs a Sigma folder to land the new data model and workbook in.

To keep this simple, we will use a plain folder and not a workspace.

Step 1: Create (or pick) a folder in Sigma.
Open your Sigma org, navigate to where you want the migrated workbook to live, and create a folder for it.

Something like:

ThoughtSpot Migration Demo

Step 2: Grab the folder ID.
Open the folder. The ID is the last segment of the URL — a short alphanumeric string, 21 characters.

Copy it from the address bar and keep it on the clipboard for the next section:

Footer

The skill's interactive scope picker is handy for exploratory runs, but for a known target — like ours — it's faster to give Claude the entire job in one message. The skill recognizes a structured kickoff prompt and skips the scope-picker decision tree entirely, going straight from "go" to convert → DM POST → workbook build → layout → parity.

Return to the terminal where Claude is paused at the scope picker, and choose Chat about this:

Paste the block below. Substitute your own values where the placeholders are:

Run /thoughtspot-to-sigma on the following. Use migrate-thoughtspot.py end-to-end and stop only if a hard gate fails.

ThoughtSpot
- TS_HOST = https://<your-tenant>.thoughtspot.cloud
- TS_TOKEN = <paste-token>
- TS_DB = QUICKSTARTS
- TS_SCHEMA = TS_RETAIL_ANALYTICS
- Model ID = <retail-analytics-worksheet-uuid>
- Liveboards = <sales-overview-ts-liveboard-uuid>

Sigma
- SIGMA_BASE_URL = <your-sigma-base-url>
- SIGMA_API_TOKEN = mint from ~/.sigma-migration/env
- SIGMA_CONNECTION_ID = <your-snowflake-connection-id>
- SIGMA_FOLDER_ID = <your-folder-id>

Options
- Name prefix: TS Retail Analytics
- RLS: Port (default)
- DM reuse: auto-pick if ≥0.6
- Parity: tolerate row-count drift between ThoughtSpot and the warehouse snapshot — this QuickStart uses a frozen CSV copy of the source, and ThoughtSpot's live data may have added rows since the export. Report the delta with a row-level diff, but treat warehouse-snapshot staleness as a soft fail (not a gate-red).

Surface the DM-reuse candidates + scores before posting, and pause for my decision if a candidate scores ≥0.6. Don't declare GREEN until assert-phase6-ran.rb exits 0 (allowing the parity tolerance above) and the visual-QA loop passes.

Claude reads the block, exports the env vars in its own bash session, runs the source-freshness preflight, then kicks off migrate-thoughtspot.py end-to-end. The rest of the run is hands-off until a gate or decision point.

Footer

When the migration completes, Claude prints a final summary covering the whole pipeline — every phase's result, the visual-QA outcome, the hard-gate verdict, and the URLs of the new Sigma data model and workbook.

The summary walks through six phases plus a visual-QA pass:

Open the new workbook in Sigma to see the migrated dashboard:

Open the data model to see how the converter wired up the joins and metrics:

Hand-polish items the skill flags rather than silently working around:

Footer

A single Liveboard is the easy case. Real migrations involve ThoughtSpot orgs with dozens or hundreds of Liveboards reading from a handful of shared models — and migrating them one-by-one through the converter loses the leverage of doing the planning work once. That's where the companion thoughtspot-assessment skill comes in.

Point thoughtspot-assessment at a ThoughtSpot org and it inventories every model, Liveboard, Answer, table, and connection, scoring each on:

The output is a Sigma-branded readout.html you can share with stakeholders, plus a ranked migration shortlist sorted by value / (1 + cost) — the cheapest, highest-value Liveboards to convert first, with tag pills like migrate-first, easy-win, needs-review, and retire.

The shortlist becomes input to a batch conversion planthoughtspot-assessment groups Liveboards that share the same underlying model, so one Sigma data model can serve a whole family of workbooks instead of producing N near-duplicate DMs. thoughtspot-to-sigma consumes that plan in batch mode and runs the conversions concurrently.

Typical flow for a real migration engagement:

  1. Run thoughtspot-assessment against the target org; review the shortlist with stakeholders.
  2. Pick the top N Liveboards to convert first — or drop the cold ones entirely.
  3. Hand the batch plan to thoughtspot-to-sigma and let it work through them.
  4. Spot-check each output; file the inevitable gap items upstream.

Footer

The following is a "grab bag" of things that might come up during real conversions, with the fix for each.

Footer

What you built is less a single conversion and more a repeatable migration path. The skill took a ThoughtSpot worksheet — model, Liveboard, search-query expressions, layout — and produced a Sigma data model, a workbook, and a parity report against the live warehouse, all from a single structured prompt. No one rebuilt the dashboard by hand, and the parity numbers are evidence rather than hope.

The patterns worth carrying into your next migration:

A first-pass conversion produces a working starting point and a documented punch list, not a hand-polished workbook. The polish loop is short, and you know exactly what to look at. That's the migration approach you can scale across an entire ThoughtSpot org.

Additional Resource Links

Blog
Community
Help Center
QuickStarts

Be sure to check out all the latest developments at Sigma's First Friday Feature page!

Footer