Skip to main content
A play watches its model and emits a run per changed row. When and how it fires is declared on definePlay — schedule, which changes count, how records enrol, and which rows are eligible. All of it deploys with cargo-ai cdk deploy.

Configure triggers in code

plays/onboarding.ts
export const onboarding = definePlay("onboarding", {
  model: contacts,
  workflow: onboardRow,
  schedule: { type: "realtime" },        // fire as rows change
  changeKinds: ["added", "updated"],     // which changes create a run
  runCreationRule: "once",               // enrol each record only once
  filter: {
    conjonction: "and",
    groups: [{
      conjonction: "and",
      conditions: [
        { kind: "string", columnSlug: "country", operator: "is", values: ["US"] },
      ],
    }],
  },
});

Schedule

The schedule field selects how the play is driven:
scheduleBehavior
{ type: "realtime" }Fire instantly as the model’s rows change
{ type: "cron", cron: "0 * * * *" }Run on a cron expression (UTC)
{ type: "dependency", play: upstream }Run after another play finishes
{ type: "watch" }Run on a watched external schedule
{ type: "dbt", jobId: "…" }Run after a dbt job completes
Real-time schedules are currently only available for HubSpot and Salesforce. The minimum interval for scheduled syncs depends on the model type (as short as 5 minutes, up to 1 day); a sync is skipped if the model was already refreshed within that window.

Change detection

changeKinds controls which row changes create a run. Defaults to ["added"].
  • Real-time schedules know exactly what happened — a row was added (created in the source) or updated.
  • Scheduled syncs (cron, dependency, watch) compare snapshots, so added means “appears in this sync but not the last” — which includes newly created rows, rows that now match the filter for the first time, and restored rows.

Enrolment rules

runCreationRule controls what happens when a record triggers repeatedly:
ValueUI equivalentBehavior
"always"Always enrolNew run every time the trigger fires for that record
"once"Enrol onceEach record is enrolled at most once, ever
"noConcurrency"If is not currently enrolledSkip if the record is already in an active run
Feedback loops with "always" + real-time on updated: if the play writes back to the source system (e.g. updating a HubSpot field), that write is itself an update event that re-triggers the play on the same record — a loop that can multiply executions by orders of magnitude. Prevent it with runCreationRule: "once" (or "noConcurrency"), by restricting changeKinds to ["added"], or by adding a filter that excludes already-processed rows (e.g. “score is unknown”).

Eligibility filter

filter (and optional sort, limit) restricts which rows are eligible. It uses the same JSON schema as the UI segment builder and the segment download CLI command.
For real-time schedules, SQL, segment, occurrence, and related-model conditions are not supported, and neither is OR within groups / AND across multiple groups.

Trigger a batch manually

Beyond the schedule, run a play on demand across a segment with the CLI:
cargo-ai orchestration play list                 # → workflowUuid, segmentUuid
cargo-ai orchestration batch create \
  --workflow-uuid <uuid> \
  --data '{"kind":"segment","segmentUuid":"<uuid>"}' \
  --wait-until-finished

Health monitoring

Set a batch health threshold (percent of runs that must succeed) and a Slack health alert for when a batch drops below it. See Monitoring for querying runs and metrics from the CLI.