← Cargo CLICONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Cargo CLI
Snapshot Sep 30, 2026 · 23:14 UTC · version 1.23.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "cargo-storage",
"description": "Work with the data inside a Cargo workspace — models (Companies, Contacts, Deals…), datasets, columns, relationships, records, and SQL over workspace storage. Triggers: \"what models do I have\", \"show me the schema\", \"add a column for\", \"how many contacts do I have\", \"SELECT … FROM\", \"query my companies table\", \"join contacts to companies\", \"what is the DDL\", \"set up a webhook-fed model\", \"where does this field live\", \"import this into a model\", \"unify these models\", \"merge duplicate accounts\", \"link contacts to companies\", \"set up a relationship between\". Skip when: querying run or batch telemetry rather than business data — use cargo-orchestration; naming a reusable filtered audience — use cargo-segmentation.",
"included_files": [
{
"relative_path": "references/examples/columns.md",
"size_in_bytes": 5387
},
{
"relative_path": "references/examples/datasets.md",
"size_in_bytes": 947
},
{
"relative_path": "references/examples/ingest-webhook.md",
"size_in_bytes": 6906
},
{
"relative_path": "references/examples/models.md",
"size_in_bytes": 2220
},
{
"relative_path": "references/examples/queries.md",
"size_in_bytes": 5065
},
{
"relative_path": "references/response-shapes.md",
"size_in_bytes": 6454
},
{
"relative_path": "references/troubleshooting.md",
"size_in_bytes": 4921
},
{
"relative_path": "skill-metadata.json",
"size_in_bytes": 1308
}
],
"skill_md_contents": "---\nname: cargo-storage\ndescription: \"Work with the data inside a Cargo workspace — models (Companies, Contacts, Deals…), datasets, columns, relationships, records, and SQL over workspace storage. Triggers: \\\"what models do I have\\\", \\\"show me the schema\\\", \\\"add a column for\\\", \\\"how many contacts do I have\\\", \\\"SELECT … FROM\\\", \\\"query my companies table\\\", \\\"join contacts to companies\\\", \\\"what is the DDL\\\", \\\"set up a webhook-fed model\\\", \\\"where does this field live\\\", \\\"import this into a model\\\", \\\"unify these models\\\", \\\"merge duplicate accounts\\\", \\\"link contacts to companies\\\", \\\"set up a relationship between\\\". Skip when: querying run or batch telemetry rather than business data — use cargo-orchestration; naming a reusable filtered audience — use cargo-segmentation.\"\nversion: \"1.2.1\"\ncompatibility: Requires @cargo-ai/cli (npm). Sign in or create an account with `cargo-ai login --email` (emailed code, no browser), `--oauth`, or an API token\nhomepage: https://github.com/getcargohq/cargo-skills\n---\n\n# Cargo CLI — Storage\n\nData layer management: inspecting and modifying models, datasets, columns, relationships, unification, and records, and running SQL queries against workspace storage.\n\n> See `references/response-shapes.md` for full JSON response structures.\n> See `references/troubleshooting.md` for common errors and how to fix them.\n> See `references/examples/models.md` for model CRUD, DDL inspection, and schema discovery examples.\n> See `references/examples/datasets.md` for dataset listing and navigation examples.\n> See `references/examples/columns.md` for column creation and management examples.\n> See `references/examples/queries.md` for `storage query execute` / `storage query download` SQL examples (WHERE, aggregations, joins, pagination, exports).\n> See `references/examples/ingest-webhook.md` for ingest (webhook-fed) models — deriving the webhook URL and POSTing records.\n\n## Bootstrap\n\nAlready signed in (`cargo-ai whoami` returns a workspace)? Skip to the next section.\n\n```bash\nnpm install -g @cargo-ai/cli # no global install? prefix every command with `npx @cargo-ai/cli`\ncargo-ai login --email you@company.com # emailed code, no browser; creates the account on first use\n # alternatives: --oauth (browser) · --token <api-token> (CI)\ncargo-ai whoami # confirm the active workspace before any write\n```\n\nEvery command prints JSON to stdout; failures exit non-zero with `{\"errorMessage\": \"...\"}`. Anything that creates a run or a batch is async — pass `--wait-until-finished` or poll the matching `get`. When the full skill bundle is installed, [`../cargo/references/prerequisites.md`](../cargo/references/prerequisites.md) adds the CLI version pin, token scopes, and the admin-only surface.\n\n## Discover resources first\n\nAlways list before inspecting or modifying.\n\n```bash\ncargo-ai storage dataset list # all datasets (uuid, slug)\ncargo-ai storage model list # all models (uuid, name, slug, columns)\ncargo-ai storage model list --dataset-uuid <uuid> # models in a specific dataset\n```\n\n**Retrieve in the UI:** models live at `app.getcargo.io/workspaces/<WORKSPACE_UUID>/models/<MODEL_UUID>`. Get `<WORKSPACE_UUID>` from `cargo-ai whoami` under `workspace.uuid`.\n\n## Quick reference\n\n```bash\ncargo-ai storage model list\ncargo-ai storage model get <model-uuid>\ncargo-ai storage model get-ddl <model-uuid>\ncargo-ai storage dataset list\ncargo-ai storage column list --model-uuid <uuid>\ncargo-ai storage relationship list\ncargo-ai storage record list --model-uuid <uuid>\ncargo-ai storage query execute \"SELECT * FROM default.companies LIMIT 10\"\ncargo-ai storage query download --query \"SELECT * FROM default.companies\"\n```\n\n## Models\n\nModels are structured tables in your workspace (e.g. Companies, Contacts).\n\n```bash\n# List all models\ncargo-ai storage model list\n\n# List models in a dataset\ncargo-ai storage model list --dataset-uuid <uuid>\n\n# Get a single model (includes columns)\ncargo-ai storage model get <model-uuid>\n\n# Get the DDL (full schema, table name and SQL dialect)\ncargo-ai storage model get-ddl <model-uuid>\n# → Useful for column discovery and SQL dialect (BigQuery vs Snowflake) before writing queries\n\n# Create a model\ncargo-ai storage model create \\\n --slug contacts \\\n --name \"Contacts\" \\\n --dataset-uuid <uuid> \\\n --extractor-slug <extractor-slug> \\\n --config '{}'\n\n# Update a model\ncargo-ai storage model update --uuid <model-uuid> --name \"New Name\"\n\n# Remove a model\ncargo-ai storage model remove <model-uuid>\n```\n\n**Querying:** Use `cargo-ai storage query execute \"<sql>\"` (or `storage query download --query \"<sql>\"` for full exports) to run SQL against storage. Tables are referenced as `<datasetSlug>.<modelSlug>` (e.g. `default.companies`) and rewritten to the underlying storage table under the hood. See [Query with SQL](#query-with-sql) below.\n\n## Ingest models (webhook-fed)\n\nA model whose extractor has `mode.kind === \"ingest\"` — `http.listenHook` and\nfriends — is filled by **pushing** records to Cargo. The app shows a \"Webhook URL\"\non the model settings screen; **no CLI command or API field returns it**, but it's\nassembled from values the CLI already exposes:\n\n```\n<baseUrl>/v1/models/<model-uuid>/records/ingest?token=<api-token>\n```\n\n```bash\nMODEL_UUID=<model-uuid>\nBASE=$(cargo-ai whoami | jq -r '.baseUrl')\nTOKEN=$(cargo-ai workspaceManagement token list | jq -r '.tokens[0].token')\necho \"$BASE/v1/models/$MODEL_UUID/records/ingest?token=$TOKEN\"\n```\n\nCheck the extractor's mode first — when it reports `\"autoIngest\": true` (calendly,\nsmartlead, instantlyV2, heyReach, cargo signals) Cargo registers the\nhook with the provider itself and the URL must **not** be handed out. Full flow,\npayload shapes, and limits: `references/examples/ingest-webhook.md`.\n\n## Datasets\n\nDatasets are logical groupings of models.\n\n```bash\n# List all datasets\ncargo-ai storage dataset list\n\n# Get a single dataset\ncargo-ai storage dataset get <dataset-uuid>\n```\n\n## Columns\n\nColumns define the schema of a model.\n\n```bash\n# List columns for a model\ncargo-ai storage column list --model-uuid <uuid>\n\n# Create a column\ncargo-ai storage column create \\\n --model-uuid <uuid> \\\n --column '{\"slug\":\"my_column\",\"type\":\"string\",\"label\":\"My Column\",\"kind\":\"custom\"}'\n\n# Update a column (pass the full column object — columns are identified by slug, not UUID)\ncargo-ai storage column update \\\n --model-uuid <uuid> \\\n --column '{\"slug\":\"my_column\",\"type\":\"string\",\"label\":\"Updated Label\",\"kind\":\"custom\"}'\n\n# Remove a column\ncargo-ai storage column remove --model-uuid <uuid> --column-slug <slug>\n\n# Reorder a column (move to a specific index)\ncargo-ai storage column reorder --model-uuid <uuid> --column-slug <slug> --to-index 2\n```\n\nColumn types: `string`, `number`, `boolean`, `date`, `object`, `array`, `vector`, `any`.\n\nColumn kinds: `custom` (user-defined), `computed` (expression over other columns), `metric` (aggregated from a related model), `lookup` (single field pulled from a related model via a join).\n\n## Preview what you built\n\nA column list doesn't tell the user whether the model is right — rows do. Two checkpoints (the pack-wide convention lives in [`../cargo/references/interaction.md`](../cargo/references/interaction.md) §4):\n\n**1. Right after `model create` / `column create` — show the schema, not rows.** A new model is empty; a `LIMIT 10` here returns nothing and reads as failure. Echo the columns as a compact table instead (column, type, what will fill it).\n\n**2. As soon as data lands — show the rows.** After a batch, play, or import writes into the model, preview it:\n\n```bash\ncargo-ai storage query execute \\\n \"SELECT * FROM <dataset-slug>.<model-slug> LIMIT 10\"\n```\n\nShow ~10 rows and only the columns that carry meaning. Storage queries are free, so this costs nothing but a few lines of output — and it's the first moment the user can actually see what they built. When a play fills a *new* column, preview that column next to the record's identifying fields (`name`, `domain`) so filled vs. empty is obvious.\n\nIf the preview comes back empty or all-null when it shouldn't, that's a finding — surface it rather than reporting the write as a success. See [`cargo-diagnostics`](../cargo-diagnostics/SKILL.md) to trace why.\n\n## Relationships\n\nRelationships link models together (e.g. Contacts belong to Companies). They are\nauthored from the CLI, not just the UI.\n\n`relationship list` takes **no flags** — it returns every relationship in the\nworkspace. Filter client-side on `fromModelUuid` / `toModelUuid`.\n\n```bash\ncargo-ai storage relationship list\n```\n\n**`relationship set` replaces the dataset's whole relationship set.** It takes a\ndataset and the complete list that should exist within it: entries carrying a\n`uuid` are updated, entries without one are created, and **any existing\nrelationship whose `uuid` is absent from the payload is deleted**. Sending one\nrelationship to a dataset that has five removes the other four. Always `list`\nfirst, then send back the full array with your addition:\n\n```bash\ncargo-ai storage relationship set \\\n --dataset-uuid <dataset-uuid> \\\n --relationships '[\n {\"uuid\":\"<existing-uuid>\",\"fromModelUuid\":\"<contacts-uuid>\",\"fromColumnSlug\":\"account_id\",\"toModelUuid\":\"<companies-uuid>\",\"toColumnSlug\":\"id\",\"relation\":\"manyToOne\"},\n {\"fromModelUuid\":\"<deals-uuid>\",\"fromColumnSlug\":\"company_id\",\"toModelUuid\":\"<companies-uuid>\",\"toColumnSlug\":\"id\",\"relation\":\"manyToOne\"}\n ]'\n```\n\n`relation` is `oneToOne`, `manyToOne`, or `oneToMany`. Both models must live in\nthe dataset you pass — relationships never span datasets, so `fromDatasetUuid`\nand `toDatasetUuid` on the response always equal `--dataset-uuid`.\n\nFailure reasons: `datasetNotFound`; `invalidRelationships` (a column slug or\nmodel UUID that doesn't resolve, or a duplicate — including the same pair stated\nin reverse); `modelNotCompatible` (see below).\n\n**Unify models refuse manual relationships.** In the native dataset, a unify\nmodel's relationships are generated during sync, so naming one as `fromModelUuid`\nor `toModelUuid` returns `modelNotCompatible`. Those auto-generated rows are also\nexcluded from the replace above, so a `set` call cannot delete them.\n\n## Unification\n\nUnification is what merges records from several source models into one canonical\naccount/contact — and it is **configurable from the CLI**, via `--unification` on\n`model update`. Pass `null` to clear it.\n\n```bash\n# Connector-driven: the integration decides how records unify\ncargo-ai storage model update --uuid <model-uuid> --unification '{\"source\":\"integration\"}'\n\n# Custom: you name the type, the matching keys, and optionally a parent\ncargo-ai storage model update --uuid <model-uuid> --unification '{\n \"source\": \"custom\",\n \"type\": \"account\",\n \"uniqueColumns\": [{\"slug\":\"domain\",\"reference\":\"domain\"}],\n \"selectedColumnSlugs\": [\"name\",\"industry\",\"employee_count\"],\n \"parent\": {\"kind\":\"model\",\"columnSlug\":\"account_id\",\"parentModelUuid\":\"<accounts-uuid>\"}\n}'\n```\n\n| Field | Applies to | Meaning |\n|---|---|---|\n| `source` | both | `integration` (connector-defined) or `custom` |\n| `type` | custom | `account`, `contact`, `accountEvent`, `contactEvent` |\n| `uniqueColumns` | custom | Match keys — `{slug, reference}` per column. This is what decides which rows are the same entity |\n| `selectedColumnSlugs` | custom | Columns carried into the unified model. Omit for all |\n| `timeColumnSlug` | custom | Event timestamp — for the two `*Event` types |\n| `parent` | custom | Links contacts/events to their account: `{\"kind\":\"model\",\"columnSlug\":…,\"parentModelUuid\":…}` or `{\"kind\":\"reference\",\"columnSlug\":…,\"reference\":…}` |\n| `filter` | custom | Segmentation filter restricting which rows unify — same `conjonction` shape as segments |\n\n**Writing the config does not recompute anything.** The unified rows are rebuilt\nby the model's sync run, so follow the update with a run and poll it:\n\n```bash\ncargo-ai storage run create --model-uuid <model-uuid>\ncargo-ai storage run list --model-uuid <model-uuid>\n```\n\nGet the current config from `storage model get <uuid>` → `unification` (`null`\nwhen the model doesn't unify). Once the run finishes, check the row count with\n`storage query execute` before treating the change as done — a too-narrow\n`uniqueColumns` under-merges and a too-broad one collapses distinct entities, and\nboth look like a successful run.\n\n## Records\n\n```bash\n# List records in a model\ncargo-ai storage record list --model-uuid <uuid>\n```\n\nFor advanced record queries (filtering, sorting, pagination), use `segmentation segment fetch` from the `cargo-orchestration` skill.\n\n## Query with SQL\n\nRun SQL against workspace storage with `storage query execute`. Tables are referenced as `<datasetSlug>.<modelSlug>` (e.g. `default.companies`) and rewritten to the underlying storage table under the hood — no DDL lookup is needed for the table name.\n\n```bash\ncargo-ai storage query execute \\\n \"SELECT name, domain FROM default.companies LIMIT 10\"\n# → { \"rows\": [...] } on success; non-zero exit with { \"errorMessage\": \"...\" } on error\n```\n\nFor full exports, use `storage query download` — it returns a signed URL to a CSV (default) or Parquet file:\n\n```bash\ncargo-ai storage query download \\\n --query \"SELECT name, domain, revenue FROM default.companies ORDER BY revenue DESC\"\n\ncargo-ai storage query download \\\n --query \"SELECT * FROM default.companies\" --format parquet\n```\n\nGet column slugs from `storage column list --model-uuid <uuid>` (or run `storage model get-ddl <model-uuid>` for the full schema and SQL dialect). Page through large result sets with `LIMIT` / `OFFSET` directly in the SQL.\n\nSee `references/examples/queries.md` for WHERE clauses, aggregations, joins, date queries, pagination, and the failure shapes returned on error.\n\n## Help\n\nEvery command supports `--help`:\n\n```bash\ncargo-ai storage model list --help\ncargo-ai storage column create --help\ncargo-ai storage relationship set --help\ncargo-ai storage query execute --help\ncargo-ai storage query download --help\n```\n"
}SHA-256: 4ae9f84ee5a1202811d3725b8b634aa35a6f46ae8c567e59e8d4b7d9690faf25