Skip to main content
A resource says what exists. An execution says what to do, once: enroll these records into this play, or run this tool on this input. You declare it in code, cargo-ai project plan shows it, and the next cargo-ai project deploy runs it after the resources are applied. There are two:
  • defineBatch runs a workflow once per record: a play, a tool, or a workflow written inline with defineWorkflow.
  • defineRun runs a workflow once, on one input: a tool or an inline workflow. A play runs on records, so it only takes a batch.
An execution acts on the outside world. A play it enrolls records into may send emails or LinkedIn actions, and reverting the code does not take them back.

Declare a batch

  • id is what Cargo remembers the execution by. It must be unique in the project: lowercase letters, digits, hyphens and underscores. Start it with a date and executions run in the order you wrote them.
  • workflow is what every record runs through: a play, a tool, or a defineWorkflow(...). An inline workflow runs as custom nodes, without being deployed as a resource.
  • data is where the records come from:
    • { kind: "filter", model, filter?, limit }: the model’s records matching the filter, at most limit. The limit is required, so a filter never runs on more records than you wrote down.
    • { kind: "segment", segment }: the records in a segment.
    • { kind: "recordIds", model, ids }: exactly these records.
    • { kind: "form", records }: records written in code, as the workflow’s form takes them. Cargo checks each against the form.
    • { kind: "file", path, mappings? }: the rows of a CSV in the project, uploaded by the deploy that runs the batch. path is relative to the project directory, and mappings renames columns to the workflow’s inputs. A file can be at most 50 MB; load larger data into a model and batch on a filter or segment.
A play batch takes any kind but file, and its model must be the play’s own. A tool or inline workflow batch takes any kind, and Cargo checks each record against the workflow’s form before it runs.

Declare a run

data is the workflow’s input. Leave it out for a workflow that takes none.

Where they live

Executions live in outputs/, in any folder under it, and every .ts file there is imported: the folder is what declares them, as infra/ does for resources, so nothing outside it is read and your scripts and tests are never run. In a project whose resources sit in infra/, that is the outputs/ at the root of the repository around it, as in a manifest repo: outputs/2026-10-14-expansion-pilot/. In any other project, it is outputs/ inside the project directory.

Plan and deploy

cargo-ai project plan lists every execution that has not run yet, and the ones that have:
An execution Cargo refused stays in the ledger and does not run again: fix it and give it a new id. cargo-ai project deploy applies the resources first, so an execution can use a play or tool created in the same change, then starts each pending execution as a batch or a run. The deploy prints each one with the batch or run it started, and exits non-zero if one did not start, without stopping the ones after it: --draft never runs executions.

Exactly once

The project’s deploy state keeps a ledger of the executions that have run, written before each one starts. It lives with the state in your workspace, so every deploy, from any checkout or from CI, reads the same one. A project whose state is still kept in cargo.state.json refuses to run executions until cargo-ai project state create moves it there. That ledger, not the code, decides what runs: There is no retry. To run something again, add an execution with a new id.