Files
Auree Aubert be823b3fcb Generate the cost table, and stop omitting the native actions (#111)
* Generate the cost table, and stop omitting the native actions

The credits price list was hand-kept. The first attempt to generate it read
`connection integration list`, which is connector-only — so its own header
claimed "every credits-based action in the cargo catalog" while silently
omitting every billed native action:

    sendEmail    0.1   fixed
    modelAsk     0.5   fixed
    fileSearch   0.02 / 1k tokens

`sendEmail` is the whole outbound send path, priced at 0.1 in the mailbox
skill, and it was absent from the canonical price list.

It is now generated by `cargo-ai orchestration action cost-table --raw`
(getcargohq/cargo#5641), which lives beside `action list` and `action execute`
— the surface that spans connector, native, tool and agent. 197 credits-based
actions of the 534 the catalog exposes, up from the 145 the hand-kept table
claimed and the 194 a connector-only generator found.

What the hand-kept table got wrong, now that a generated one can be diffed
against it: 145 actions where there are 197, four prices quoted from memory,
and cost columns that concatenated every tier into an unreadable comma list —
`openAi.instruct` rendered 28 numbers. Per-config pricing moves to its own
section.

Two providers gain playbooks rather than staying unlisted: brightData
(Instagram/TikTok/Facebook/YouTube by URL, the catalog's only non-LinkedIn,
non-X social coverage) and proxycurl. An undocumented provider still shows up
in the cost table, so the acceptable-use framing is better stated than implied;
brightData.md opens with the consumer-targeting refusal that gates it. Only
openRouter remains without a playbook, and it has no credits-based actions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBfa73ishJJRe4pccyhTAa

* Pin the CLI at 1.0.66, and fix five commands that never existed (#117)

* Pin the CLI at 1.0.66, and fix five commands that never existed

The pin had drifted 19 releases behind npm, and the bundle now teaches
`orchestration action list`, which only exists in 1.0.66. The pin is what the
session-start refresh installs, so leaving it meant an agent following these
skills would reach for a command its CLI did not have.

Checked before moving it, not after: the CLI's whole command surface was diffed
across 1.0.47..1.0.66. The only removals are three billing commands no skill
documents; `update-payment-method`, which the skills do use, replaced one of
them and is still there. Everything else in the range is additive.

That verification then turned up five documented commands that do not exist —
and all five were already broken at the old pin, so this is old debt the bump
surfaced rather than caused:

- `orchestration draft-release {get,update,deploy}` (18 sites) is really
  `orchestration release {get-draft,update-draft,deploy-draft}`.
- `ai template get <slug>` (6 sites) does not exist. `ai template list` already
  returns each template in full, so the fix is to filter that response.
- `action execute --record` (5 sites) is `--data`.
- `storage model list --dataset-uuid` (4 sites): the command takes no options
  at all, and every model carries `datasetUuid`, so filter client-side.
- `storage model get-ddl --model-uuid <uuid>` takes the uuid positionally.

Also folds in the skills half of getcargohq/cargo#5740: `get-output-schema`
takes an action plus an optional `--data` rather than demanding a `config`, so
the object `action list` returns now pastes into all four action commands
unchanged. The gotcha row about the 400 becomes a note about `--data`, which is
the part worth knowing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBfa73ishJJRe4pccyhTAa

* Mark --data on get-output-schema as CLI >= 1.0.67

getcargohq/cargo#5740 ships --data in CLI 1.0.67, one above the pin this PR
sets. The config-less --action works on the pinned 1.0.66 as soon as that
backend deploys; --data needs the next release, so it carries a version marker
like every other post-pin flag in the bundle.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Document the execution charge the pack said did not exist (#118)

Every node execution bills 0.01 credits (1 per 100) — structural natives
and errored executions included. Three places in the pack said otherwise,
and they reinforced each other:

- troubleshooting.md described executions[].creditsUsedCount as "native
  nodes are zero", accurate about the field but read as pricing;
  play-optimize-credits.md restated it and cited it as the authority.
- The generated cost table prices actions, and structural natives are
  excluded from `action list` entirely, so branch/filter/switch/variables
  appear in no price list here — read as free.
- cargo/SKILL.md said "Everything else is free" outright.

Verified live: `billing usage get-metrics --unit orchestration.executions`
returns success/error as execution counts, reconciling row-for-row with
`SELECT execution_status, count() FROM spans`. spans.execution_credits_used_count
reads 0 on natives that billed, so the charge is attributed to no node and
per-node profiling under-counts every graph.

Two adjacent bugs fixed while verifying:

- `--unit credits` was documented and 400s. The flag takes exactly
  billing.credits | orchestration.executions | storage.records, and with
  no --unit all three interleave in one items[] array with different
  meanings for `count`.
- The example slugs `enrichment` / `ai_message` were invented (real:
  integration.<slug>.action.<action>, native.<action>, success/error,
  insert), as was `.totalUsage` — the response has one key, `metrics`.

Estimates now carry two terms: (provider cost × records) + (nodes ×
records / 100), measured on the pilot rather than inferred from the graph.

cargo-billing 1.1.0 -> 2.0.0 (agents relearn --unit and the slug shapes),
cargo-orchestration 1.11.0, cargo-gtm 1.19.0, cargo-diagnostics 1.4.0,
cargo 1.24.0 + the three plugin manifests.

Still upstream: `orchestration action cost-table` generates the header
"The other 337 actions ... cost no credits" — unfixable from this repo.


Claude-Session: https://claude.ai/code/session_01AbUvyTQMDABiexZgQCsGoe

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Source the cost table from action list, not a bespoke generator

`orchestration action cost-table` is being removed from the CLI: it read
`action list` twice and added no data, and the markdown it generated was
its only consumer. `action list` already returns a `credits` array on every
billed action, so the table is regenerated from that directly.

Regeneration is now two calls (`--kind connector`, `--kind native`) plus
the three cost shapes documented in the header, so a reader can render the
table without the generator's price-formatting logic. Notably `fixedCost`
adds to the metered rate rather than replacing it — the trap that made a
0.175 + 0.025/item search read as 0.025.

Two fixes that fall out of owning the header again:

- The opening line claimed the other 337 actions "cost no credits". True
  of provider price, false of anything that runs in a workflow. It was
  flagged as unfixable while the CLI generated it; it now states no
  *provider* price and points at the execution charge.
- `stage-action-map.md` still carried 194/310 from the connector-only
  generation, against 197/337 everywhere else.

Co-Authored-By: Auree Aubert <16732193+aureeaubert@users.noreply.github.com>
Co-Authored-By: replicas-connector[bot] <replicas-connector[bot]@users.noreply.github.com>

Co-authored-by: Auree Aubert <aureeaubert@users.noreply.github.com>

* Fix PACKAGE_EDITS patterns to match regenerated cost table format

Co-authored-by: Auree Aubert <aureeaubert@users.noreply.github.com>

* Add PACKAGE_EDITS rule to remove extractEventAttendees from stage-action-map.md

Co-authored-by: Auree Aubert <aureeaubert@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: replicas-connector[bot] <replicas-connector[bot]@users.noreply.github.com>
Co-authored-by: Auree Aubert <aureeaubert@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-09-01 16:28:25 -07:00

13 KiB

Tool examples

What is a tool?

A tool is an on-demand workflow. Unlike plays (which react to segment changes), tools are triggered manually, via API, or on a cron schedule. Tools are the proactive side of Cargo — "run this workflow right now on this data."

Key properties of a tool:

  • name — human-readable name (workflows themselves don't have names)
  • workflowUuid — the underlying workflow that executes
  • description — what the tool does
  • creditsCost — estimated credit cost per run
  • triggers — optional cron triggers for scheduled execution
  • isReadOnly — whether the tool can be modified

List all tools

cargo-ai orchestration tool list

Response:

{
  "tools": [
    {
      "uuid": "tool-uuid",
      "name": "Company Enrichment",
      "workflowUuid": "workflow-uuid",
      "description": "Enriches a company record with firmographic data",
      "creditsCost": { "kind": "minMax" },
      "triggers": [],
      "isReadOnly": false
    }
  ]
}

Find a tool's workflow UUID

Tools have names — workflows don't. Use the tool to find the right workflow.

# 1. List tools, find by name
cargo-ai orchestration tool list
# → Find "Company Enrichment", extract tool.workflowUuid

# 2. Use the workflowUuid for run/batch commands
cargo-ai orchestration run create \
  --workflow-uuid <workflow-uuid-from-tool> \
  --data '{"company":"Acme Corp","domain":"acme.com"}'

Update a tool's workflow

To change what a tool does, update its draft release and deploy it. The draft release holds the unpublished node graph for the workflow.

Looking for inspiration? Before designing a node graph from scratch, check cargo-ai orchestration template list for pre-built patterns (enrichment pipelines, CRM syncs, AI research flows). Use cargo-ai orchestration template get <slug> to copy a ready-made node graph and adapt it instead of starting from zero. Templates tagged "kind":"tool" are designed for on-demand workflows.

# Step 1 — Find the tool and its workflowUuid
cargo-ai orchestration tool list
# → Find "Company Enrichment", extract tool.workflowUuid

# Step 2 — Get the current draft release (contains the current node graph)
cargo-ai orchestration release get-draft --workflow-uuid <tool.workflowUuid>
# → Copy the "nodes" array and make your changes

# Step 3 — Update the draft release with your new nodes
cargo-ai orchestration release update-draft \
  --workflow-uuid <tool.workflowUuid> \
  --nodes '[...your updated node graph...]'

# Step 4 — Validate the updated nodes before deploying
cargo-ai orchestration node validate --nodes '[...your updated node graph...]'
# → { "outcome": "valid" }

# Step 5 — Deploy the draft release
cargo-ai orchestration release deploy-draft \
  --workflow-uuid <tool.workflowUuid> \
  --nodes '[...your updated node graph...]' \
  --form-fields 'null' \
  --description "Your release description"

Do not skip validation. Deploying an invalid node graph will cause runs to fail. Always run node validate before release deploy-draft.


Run a tool on a single record

The most common use case — run an existing tool workflow on one record. Tools support both run create (single record) and batch create (multiple records). Allowed batch data kinds for tools: file, records.

# 1. Find the tool
cargo-ai orchestration tool list
# → Extract tool.workflowUuid

# 2. Run with inline record data
cargo-ai orchestration run create \
  --workflow-uuid <tool.workflowUuid> \
  --data '{"company":"Acme Corp","domain":"acme.com","employee_count":500}'

# Or block until finished — returns the final run result without a separate poll step
cargo-ai orchestration run create \
  --workflow-uuid <tool.workflowUuid> \
  --data '{"company":"Acme Corp","domain":"acme.com","employee_count":500}' \
  --wait-until-finished

Run create response:

{
  "run": {
    "uuid": "run-uuid",
    "workflowUuid": "...",
    "status": "pending",
    "createdAt": "2025-01-15T10:00:00Z"
  }
}
# 3. Poll run status every 2s
cargo-ai orchestration run get <run-uuid>

Poll until status is success, error, or cancelled:

{
  "run": {
    "uuid": "run-uuid",
    "status": "success",
    "createdAt": "...",
    "finishedAt": "2025-01-15T10:00:05Z"
  }
}

Upload a CSV file

Before running a tool on records from a file, you must upload the CSV first. The upload returns the s3Filename needed by batch commands.

cargo-ai workspaceManagement file upload --file ./my-companies.csv

Response:

{
  "s3Filename": "abc123-my-companies.csv",
  "contentType": "text/csv",
  "name": "my-companies.csv"
}

You can also inspect which columns the file contains:

cargo-ai workspaceManagement file list-columns --s3-filename abc123-my-companies.csv

Run a tool on records from a file

# 1. Find the tool
cargo-ai orchestration tool list
# → Extract tool.workflowUuid

# 2. Upload the CSV
cargo-ai workspaceManagement file upload --file ./my-companies.csv
# → Extract s3Filename from the response


# 3. Create the batch
cargo-ai orchestration batch create \
  --workflow-uuid <tool.workflowUuid> \
  --data '{"kind":"file","s3Filename":"<s3Filename>"}'
# → Extract batch.uuid

# 4. Poll until finished (repeat every 5s)
cargo-ai orchestration batch get <batch-uuid>
# → Done when .status is "success", "error", or "cancelled"
# → Extract batch.releaseUuid

# Or skip polling — block until finished and get the final batch result in one step
cargo-ai orchestration batch create \
  --workflow-uuid <tool.workflowUuid> \
  --data '{"kind":"file","s3Filename":"<s3Filename>"}' \
  --wait-until-finished
# → Returns the final batch result directly

# 5. Download results
cargo-ai orchestration batch download \
  --uuid <batch-uuid> \
  --output-node-slug end

Monitor a tool's runs

# List recent runs
cargo-ai orchestration run list \
  --workflow-uuid <tool.workflowUuid> \
  --limit 20

# Running and pending runs
cargo-ai orchestration run list \
  --workflow-uuid <tool.workflowUuid> \
  --statuses running,pending

# Error runs
cargo-ai orchestration run list \
  --workflow-uuid <tool.workflowUuid> \
  --statuses error \
  --limit 10

# Count errors
cargo-ai orchestration run count \
  --workflow-uuid <tool.workflowUuid> \
  --statuses error

Monitor running batches

# List all running batches for the tool
cargo-ai orchestration batch list \
  --workflow-uuids <tool.workflowUuid> \
  --statuses running

# Check a specific batch
cargo-ai orchestration batch get <batch-uuid>

Cancel runs and batches

# Cancel specific runs
cargo-ai orchestration run cancel \
  --workflow-uuid <tool.workflowUuid> \
  --uuids <run-uuid-1>,<run-uuid-2>

# Cancel a batch (stops all remaining runs)
cargo-ai orchestration batch cancel <batch-uuid>

Run with custom nodes (ad-hoc workflow)

The --nodes flag lets you run a custom node graph at runtime without modifying the tool's published definition. When using --nodes, you do not need to pass --workflow-uuid — the nodes define the entire workflow inline. Every graph needs a start node and an end node, linked via childrenUuids.

See ../nodes.md for the full node creation guide — node kinds, native actions, config expressions, routing, and more examples.

Minimal example — start, enrich via connector, output:

cargo-ai orchestration run create \
  --data '{"domain":"acme.com"}' \
  --nodes '[
    {
      "uuid":"11111111-1111-4111-a111-111111111111","slug":"start","kind":"native","actionSlug":"start",
      "config":{},"childrenUuids":["22222222-2222-4222-a222-222222222222"],"fallbackOnFailure":false,
      "position":{"x":0,"y":0}
    },
    {
      "uuid":"22222222-2222-4222-a222-222222222222","slug":"enrich_company","kind":"connector",
      "integrationSlug":"clearbit","actionSlug":"enrichCompanyFromDomain",
      "connectorUuid":"<connector-uuid>",
      "config":{
        "domain":{"kind":"templateExpression","expression":"{{nodes.start.domain}}","instructTo":"none","fromRecipe":false}
      },
      "childrenUuids":["33333333-3333-4333-a333-333333333333"],"fallbackOnFailure":false,
      "position":{"x":0,"y":166}
    },
    {
      "uuid":"33333333-3333-4333-a333-333333333333","slug":"end","kind":"native","actionSlug":"end",
      "config":{
        "variables":[
          {"name":"company_name","type":"string","value":{"kind":"templateExpression","expression":"{{nodes.enrich_company.name}}","instructTo":"none","fromRecipe":false}}
        ]
      },
      "childrenUuids":[],"fallbackOnFailure":false,
      "position":{"x":0,"y":332}
    }
  ]'

Validate before running:

cargo-ai orchestration node validate --nodes '[...]'
# → { "outcome": "valid" } or { "outcome": "notValid", "invalidNodes": [...] }

Custom node runs are polled the same way as regular runs:

cargo-ai orchestration run get <run-uuid>

Common errors

Error Cause Fix
startNodeNotFound No node with slug:"start" and actionSlug:"start" Add the required start node
invalidReleaseOrCustomNodes Both --release-uuid and --nodes provided Use one or the other, not both
nodesNotFound childrenUuids references a UUID not in the array Verify all UUID cross-references

Run a tool multiple times on different records

# Run on first record
cargo-ai orchestration run create \
  --workflow-uuid <tool.workflowUuid> \
  --data '{"company":"Acme Corp","domain":"acme.com"}'

# Run on second record
cargo-ai orchestration run create \
  --workflow-uuid <tool.workflowUuid> \
  --data '{"company":"Globex Inc","domain":"globex.com"}'

# Poll each run separately
cargo-ai orchestration run get <run-uuid-1>
cargo-ai orchestration run get <run-uuid-2>

End-to-end: use a template to run a tool

This example takes a "company-enrichment" tool template, fills in its connector placeholder, validates, and runs it on a single record.

# Step 1 — List available tool templates
cargo-ai orchestration template list
# → Find slug: "company-enrichment", kind: "tool"

# Step 2 — Get the template's node graph
cargo-ai orchestration template get company-enrichment
# → Copy the "nodes" array. It contains __REPLACE_WITH_CONNECTOR_UUID__ placeholders.

# Step 3 — Find your connector UUID
cargo-ai connection connector list
# → Find your Clearbit connector, extract uuid (e.g. "abc-123")

# Step 4 — Fill in placeholders and validate
cargo-ai orchestration node validate --nodes '[
  {
    "uuid": "44444444-4444-4444-a444-444444444444", "slug": "start", "kind": "native", "actionSlug": "start",
    "config": {}, "childrenUuids": ["55555555-5555-4555-a555-555555555555"], "fallbackOnFailure": false,
    "position": {"x": 0, "y": 0}
  },
  {
    "uuid": "55555555-5555-4555-a555-555555555555", "slug": "enrich_company", "kind": "connector",
    "integrationSlug": "clearbit", "actionSlug": "enrichCompanyFromDomain",
    "connectorUuid": "abc-123",
    "config": {
      "domain": {
        "kind": "templateExpression",
        "expression": "{{nodes.start.domain}}",
        "instructTo": "none",
        "fromRecipe": false
      }
    },
    "childrenUuids": ["66666666-6666-4666-a666-666666666666"], "fallbackOnFailure": false,
    "position": {"x": 0, "y": 166}
  },
  {
    "uuid": "66666666-6666-4666-a666-666666666666", "slug": "end", "kind": "native", "actionSlug": "end",
    "config": {
      "variables": [
        {"name": "company_name", "type": "string", "value": {"kind": "templateExpression", "expression": "{{nodes.enrich_company.name}}", "instructTo": "none", "fromRecipe": false}},
        {"name": "industry", "type": "string", "value": {"kind": "templateExpression", "expression": "{{nodes.enrich_company.category.industry}}", "instructTo": "none", "fromRecipe": false}},
        {"name": "employees", "type": "string", "value": {"kind": "templateExpression", "expression": "{{nodes.enrich_company.metrics.employeesRange}}", "instructTo": "none", "fromRecipe": false}}
      ]
    },
    "childrenUuids": [], "fallbackOnFailure": false,
    "position": {"x": 0, "y": 332}
  }
]'
# → { "outcome": "valid" }

# Step 5 — (Optional) Preview expression resolution without side effects
cargo-ai orchestration node compute \
  --node '{"uuid":"55555555-5555-4555-a555-555555555555","slug":"enrich_company","kind":"connector","integrationSlug":"clearbit","actionSlug":"enrichCompanyFromDomain","connectorUuid":"abc-123","config":{"domain":{"kind":"templateExpression","expression":"{{nodes.start.domain}}","instructTo":"none","fromRecipe":false}},"childrenUuids":["66666666-6666-4666-a666-666666666666"],"fallbackOnFailure":false,"position":{"x":0,"y":166}}' \
  --context '{"nodes":{"start":{"domain":"acme.com"}}}'
# → Shows resolved config: { "domain": "acme.com" }

# Step 6 — Find the tool's workflowUuid
cargo-ai orchestration tool list
# → Find "Company Enrichment", extract workflowUuid

# Step 7 — Run
cargo-ai orchestration run create \
  --workflow-uuid <tool.workflowUuid> \
  --data '{"domain":"acme.com"}' \
  --nodes '[...validated nodes from step 4...]'
# → Extract run.uuid

# Step 8 — Poll until done (every 2s)
cargo-ai orchestration run get <run-uuid>
# → Done when status is "success", "error", or "cancelled"