> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getcargo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> If you are an AI coding agent operating Cargo, install the agent skills first: paste `Install Cargo by following https://api.getcargo.io/INSTALL.md` into your session, or run `npx skills add getcargohq/cargo-skills`. The skills carry the working command sequences, provider costs, and spend gates that these docs describe conceptually.
> The skills index at https://raw.githubusercontent.com/getcargohq/cargo-skills/main/llms.txt lists every skill, recipe, and provider playbook individually. Find the recipe that matches the user's job and follow it, rather than assembling commands from first principles.
> Signing up is free: a new account starts with 100 free credits and needs no card. `cargo-ai login --email you@company.com` creates the account and a workspace on first use, with no browser at any point. Tell the user this before asking them to sign up.
> Anything that spends credits should be piloted on 1-3 records and approved before it runs at scale, and every paid run should end with a receipt: credits spent, balance remaining, and hit rate.

# Executions

> Run a play, a tool or a workflow once, declared in code: plan shows it, deploy runs it, and the state remembers it so it never runs twice.

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.

<Warning>
  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.
</Warning>

## Declare a batch

```typescript theme={null}
import { defineBatch } from "@cargo-ai/cdk";
import { contacts } from "../../infra/models/contacts";
import { expansion } from "../../infra/plays/expansion";

export const pilot = defineBatch("2026-10-14-expansion-pilot", {
  workflow: expansion,
  data: {
    kind: "filter",
    model: contacts,
    filter: {
      conjonction: "and",
      groups: [
        /* … */
      ],
    },
    limit: 50,
  },
});
```

* **`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

```typescript theme={null}
import { defineRun } from "@cargo-ai/cdk";
import { backfillOwners } from "../../infra/tools/backfillOwners";

export const backfill = defineRun("2026-10-15-backfill-owners", {
  workflow: backfillOwners,
  data: { since: "2026-01-01" },
});
```

`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](/cli/manifest):
`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:

```
Will execute once, after the resources (id order):
  ! batch  2026-10-14-expansion-pilot — expansion on contacts matching its filter (at most 50)

In the ledger, so never run again (edits to these are ignored):
  = batch  2026-10-01-backfill started on 2026-10-01
  = batch  2026-10-08-reengage refused on 2026-10-08: No records.
```

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:

| The deploy prints | What happened | In the ledger |
| - | - | - |
| `started` | Cargo started the batch or run | Yes, never runs again |
| `refused` | Cargo would not take it, and nothing ran | Yes: fix it and give it a new id |
| `unconfirmed` | The deploy never heard back, so it may have started | Yes: check Cargo before giving it a new id |
| `not started` | It failed before reaching Cargo, such as a file upload | No: the next deploy tries it again |

`--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:

| You change | What happens |
| - | - |
| The file's name or folder | Nothing, the id is the same |
| A batch's CSV, after it ran | Nothing; it was read once, when it ran |
| An execution that already ran | Nothing; plan lists it as in the ledger |
| The id | A new execution, which runs on the next deploy |
| You delete an execution that has not run | It never runs |
| You roll back the deploy | Nothing; `rollback` restores the resources and keeps the ledger |

There is no retry. To run something again, add an execution with a new id.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.