with one click
build-carto-workflow
How to write, validate, and upload CARTO Workflows
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
How to write, validate, and upload CARTO Workflows
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
How to use the CARTO CLI to interact with the platform
How to enrich component notes and input type documentation served by the local workflows-api
Builds Geographically Weighted Regression (GWR) workflows in CARTO. Triggers when the user mentions GWR, geographically weighted regression, spatially varying relationships, local regression, local coefficients, spatial regression, "what drives X in different areas", "why do prices vary spatially", "local factors affecting Y", varying coefficients, coefficient maps, spatial non-stationarity, or wants to model how the relationship between a dependent variable and predictors changes across geography. Produces per-cell regression coefficients that reveal how predictor importance shifts from place to place.
Builds Getis-Ord Gi* hotspot analysis workflows in CARTO. Triggers when the user mentions hotspots, coldspots, spatial clusters, Getis-Ord, Gi*, cluster detection, concentration areas, "where do X cluster", spacetime hotspot, temporal clusters, time-varying patterns, hotspot trends, emerging hotspots, Mann-Kendall, or wants to find statistically significant spatial or spatiotemporal patterns in point or grid data.
Builds Moran's I spatial autocorrelation workflows in CARTO. Triggers when the user mentions spatial autocorrelation, Moran's I, spatial dependency, spatial correlation, spatial outliers, HH HL LH LL quadrants, high-high clusters, low-low clusters, spatial weight matrix, "is there clustering", "are values spatially correlated", local indicators of spatial association, LISA, spatial randomness test, or wants to determine whether a variable exhibits spatial clustering, dispersion, or randomness across a gridded dataset. Also relevant when the user needs to classify locations into cluster types (HH, HL, LH, LL) rather than just identifying hotspots and coldspots.
Guides building ML pipelines in CARTO Workflows when the user wants to train a model, predict, classify, forecast, or do regression. Triggers on machine learning, ML, prediction, classification, regression, forecasting, churn, predict, train model, BigQuery ML, Snowflake ML, BQML, ARIMA, time series prediction.
| name | build-carto-workflow |
| description | How to write, validate, and upload CARTO Workflows |
This skill contains everything needed to build CARTO workflows:
Component schemas, input type formats, and gotchas are served by the CLI — never hardcode or assume them.
Follow these 6 phases in order for every workflow request. Do not skip or reorder phases.
Goal: Understand what the user wants and collect all necessary inputs.
Identify data sources:
find-tables skill to discover tablesClarify the goal: What transformation? What output? What filters/conditions?
Determine connection:
carto connections list | head -n 20
Fetch component catalog:
carto workflows components list --connection <connection> --json
This is your ONLY source of truth for component names.
Goal: Gather component details and prepare a plan.
Select components from the catalog you fetched
Fetch schemas for ALL components you plan to use:
carto workflows components get <name1>,<name2>,<name3> --connection <connection> --json
The response includes inputs, outputs, and notes. The notes array contains gotchas — read them carefully.
Fetch input type formats for the components you selected:
carto workflows components get <component1>,<component2>,<component3> --connection <connection> --input-formats --json
Pass component names (e.g. native.buffer,native.spatialjoin), NOT input type names. The --input-formats flag returns format, examples, and pitfalls for each input/output type used by those components. This is your reference for how to set parameter values.
Design principles:
native.customsqlgeom, h3, quadbinGoal: Get user agreement before building.
Goal: Implement iteratively, validating frequently.
Create workflow file with basic structure (see JSON Structure)
Build in phases, validating after each:
# Offline structural check (fast, no auth needed)
carto workflows validate workflow.json --json
# Deep warehouse-aware check (column types, table existence, AT resolution)
carto workflows verify workflow.json --connection <connection-name> --json
Fix errors silently - don't expose implementation details to user
Iterate until complete and validated
carto workflows create --file workflow.json --verify
The connection comes from connectionId inside the bundle — no --connection flag needed here.{
"connectionId": "<uuid from carto connections list>",
"title": "Workflow Title",
"description": "What this workflow does",
"config": {
"schemaVersion": "1.0.0",
"connectionProvider": "bigquery | snowflake | redshift | postgres | databricksWarehouse | oracle",
"nodes": [],
"edges": [],
"variables": []
}
}
| Field | Required | Description |
|---|---|---|
connectionId | Yes (for create/verify) | UUID of the CARTO connection — get it via carto connections list --json |
title | Yes | Display name |
config.schemaVersion | Yes | Always "1.0.0" |
config.connectionProvider | Yes | Must match the connection's provider: bigquery, snowflake, redshift, postgres, databricksWarehouse, oracle |
config.nodes | Yes | Array of workflow components |
config.edges | Yes | Array of connections between nodes |
config.variables | No | Optional array of workflow variables |
Important: The connectionProvider value must match the actual provider of the connection you use for validation and execution. Using the wrong value causes SQL generation to use the wrong dialect. Check provider with carto connections list --search <name> --json (note: carto connections get requires a UUID, not a name).
On update, the config wrapper is optional (you can patch top-level fields like title independently); on create it is required and must contain nodes and edges (empty arrays are OK).
{
"id": "unique-node-id",
"type": "generic",
"data": {
"name": "native.componentname",
"version": "2",
"label": "Display Label",
"inputs": [
{ "name": "source", "type": "Table", "value": "" }
],
"outputs": [
{ "name": "out", "type": "Table" }
]
},
"position": { "x": 100, "y": 100 }
}
id: Unique identifier (use descriptive names like source-accidents, filter-type)type: Always "generic" for processing nodes. Source nodes (native.gettablebyname) also use "generic".data.name: Component name from catalog (e.g. native.buffer)data.version: Component version as string. Include always — check the component schema for the current version.data.inputs: Array of { "name": "...", "type": "...", "value": "..." } objects. Not a key-value params object — must be an array.data.outputs: Array of { "name": "...", "type": "Table" } objects. Get exact names from component schema.position: Required. Layout coordinates (left-to-right, ~200px spacing). Every node must have a position.{
"id": "edge-source-to-target",
"source": "source-node-id",
"target": "target-node-id",
"sourceHandle": "out",
"targetHandle": "source"
}
Handle names must match component schema exactly.
{
"variables": [
{ "id": "var-1", "name": "distance_meters", "type": "Number", "defaultValue": "1000" }
]
}
Reference with {{variable_name}} syntax.
Do not rely on memorized component schemas or input formats. Always fetch live data from the CLI.
| Command | Purpose |
|---|---|
carto workflows components list --connection <conn> --json | List all available components |
carto workflows components get <names> --connection <conn> --json | Get component schemas with inputs, outputs, and notes (gotchas) |
carto workflows components get <names> --connection <conn> --input-formats --json | Get input type format, examples, and pitfalls for the types used by those components. Pass component names (e.g. native.buffer), not input type names. |
notes: Array of gotcha strings — non-obvious behavior, deprecated status, output column naming, etc.format: Prose describing the expected value shape and structureexamples: Concrete JSON snippets showing correct usagepitfalls: Common mistakes — required-but-not-obvious fields, evaluation order, format quirksWhen things go wrong, see the troubleshooting/ folder:
| Issue Type | Guide |
|---|---|
| Validation fails | validation.md - Error patterns and fixes |
| Execution fails | execution.md - Runtime errors, debugging |
| Unexpected behavior | gotchas.md - CLI and design quirks |
| Error Pattern | Fix |
|---|---|
| "column not found" | Check exact name with carto connections describe (note: Snowflake uppercases columns) |
| "table not found" | Verify FQN format matches provider (see providers/) |
| "connection failed" | Run carto auth status, then carto auth login |
| Empty results (0 rows) | Filters too restrictive; check join keys; verify case sensitivity |
| Validate passes but execution fails | Run carto workflows verify --connection <conn> for full warehouse-aware validation |
Different data warehouse providers have different SQL dialects, table naming conventions, and known limitations. See the provider-specific guides:
| Provider | Guide |
|---|---|
| BigQuery | providers/bigquery.md |
| Snowflake | providers/snowflake.md |
| Databricks | providers/databricks.md |
Key differences: Table FQN format, column casing, geometry handling, Analytics Toolbox path, schedule expression syntax, and SQL dialect. Always check the provider guide when working with a non-BigQuery connection.
When using ColumnsForJoin inputs (e.g. in native.joinv2, native.spatialjoin), an empty array [] means include ALL columns from that side of the join. To select specific columns, list them explicitly as [{"name":"col","joinname":"alias"}].
Node inputs must be an array of { "name", "type", "value" } objects:
"inputs": [
{ "name": "source", "type": "Table", "value": "" },
{ "name": "column", "type": "Column", "value": "geom" }
]
Do NOT use a params/key-value object format — the engine expects an array.
Comma-separated column,method pairs: "population,sum,area,avg,name,count". You can aggregate the same column multiple times: "N_BIKES,sum,N_BIKES,avg,N_BIKES,count".
Some components (e.g. gettablebyname) return "type": "View" in their output schema, while downstream components expect "type": "Table" inputs. These are interchangeable for edge connections — you can connect a View output to a Table input.
carto workflows validate is offline (Zod-only) and cannot resolve Analytics Toolbox location. For workflows that use AT components (H3, Quadbin, Getis-Ord, enrichment, etc.), always run carto workflows verify --connection <conn> for the warehouse-aware checks that include AT resolution.
| Example | Description |
|---|---|
| Filter and Count | Read table, filter rows, count results |
| Bike Accidents Near Parkings | Buffer, spatial join, aggregation |
When workflow is complete, load session-wrapup skill to document the session.