Capability
plungeai-campaigns
Run a list to completion on PlungeAI: the campaign ledger (claim/complete/fail/retry), the campaign-config (list source, cycle, cadence, retries, delivery), and how a campaign keeps going via cron or self-scheduling runAgain. A campaign is a saved workflow of kind campaign: create it over the One API (POST /v1/workflows with kind: campaign + campaign_config), MCP (plungeai_workflow) or Studio. Use when the user wants to process every row of a table on a cadence, run a batch job until a list is drained, or build a continuous monitor over a fixed set of items. Ledger status, pause and stop are Studio-session routes (ocean-cli campaigns); authoring UI: plungeai-campaign-agent; for the pipeline steps use plungeai-workflows.
Download zip (opens in a new tab) · View raw SKILL.md (opens in a new tab)
A campaign claims a list of items and works through them with per-item retries on
a repeating cadence, until the cycle is drained — the pattern behind "check every
row in this table weekly" or "watch these 50 URLs continuously." Its runtime is the
campaign ledger: a small set of agent: data-table-agent operations
(claim/complete/fail/release/status) that a CNL type: batch task with
ledger: campaign calls automatically.
Prerequisites
- A self-service
ozk_API key from Dashboard → One API → Keys (https://dashboard.plungeai.com (opens in a new tab)) for REST (https://api.plungeai.com) and MCP (https://mcp.plungeai.com/v1), or build the pipeline in Ocean Studio. - A campaign is a saved workflow with
kind: campaign. REST, MCP and Studio create the same row; the ledger operations below are the engine's own (data-table-agentis an internal agent with no registry card — you do not discover or call it, you write it into the campaign YAML and the platform arms the ledger at save).
Over the One API, MCP and CLI
| Job | REST (ozk_ key) | MCP | CLI ocean-cli … |
|---|---|---|---|
| create | POST /v1/workflows {name, kind: "campaign", yaml, campaign_config, folder?, description?} → 201 {workflow, warnings?} | plungeai_workflow {action: "create", kind: "campaign", name, yaml, campaign_config} | workflows create then campaigns setup ID --config @campaign.json (Studio session) |
| list, read | GET /v1/workflows?kind=campaign → {workflows, total, limit, offset, has_more}; GET /v1/workflows/{id} | plungeai_list_workflows {kind: "campaign"}; plungeai_workflow {action: "get"} | workflows list --kind campaign |
| change, delete | PATCH /v1/workflows/{id}; DELETE /v1/workflows/{id} → 204; versions: GET|POST /v1/workflows/{id}/versions | plungeai_workflow update / delete / save_version | workflows update, delete, versions |
| cadence | the campaign's job is a schedule: GET /v1/schedules, then POST /v1/schedules/{id}/pause | resume | run | plungeai_schedule list / pause / resume / run_now | schedules … |
| a campaign's runs | GET /v1/executions?workflow_id=<campaign id> | plungeai_executions {action: "list"} | executions list |
| ledger status, pause, stop | — (Studio session only) | — | campaigns status | pause | resume | stop | complete ID |
curl -s -X POST https://api.plungeai.com/v1/workflows \
-H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \
-d "$(jq -n --rawfile yaml watch.yaml '{name: "Status-page watch", kind: "campaign", yaml: $yaml,
campaign_config: {list: {inline: ["https://status.example-a.com", "https://status.example-b.com"]},
cycle: "continuous", schedule: "0 * * * *", max_attempts: 3}}')"What builders get wrong:
campaign_configis JSON on REST and MCP (thecampaign-configfenced block is the Studio spelling of the same fields):listwith exactly one oftable,agent,csv,inline;cycle;max_attempts(integer ≥ 1) are required;cycle_start,schedule(5-field cron),batch_size,max_items,pace,then,deliver,localare optional.422 invalid_paramsnames the field and nothing is created;kindother thancampaignwith acampaign_configis422too. The Studio-onlytask_typesandlearnkeys are dropped.- A
201can still carrywarnings:campaign setup did not complete — the workflow is saved without its ledger,Ledger not created: …, or a rejectedschedule. Read them; the row exists either way. - No
schedulemeans no scheduler job. The ids of the ledger and the job are not in the201: find the job withGET /v1/schedules(named<name> - Campaign). For a campaign you build over the API, setschedule. - The save is linted (
422 invalid_workflow,errorslisted): exactly ONEagent: data-table-agent,operation: campaignClaimtask and ONEtype: batchtask withitems_fromandledger: campaign;concurrency≤ 5; noask_userorplatform_actioninside the batch (it is unattended); an innertype: harnesstask liststask_completeinallowed_tools;max_itemsis required when an inner task can reachdata-table-agent. DELETEis a teardown, not a cascade: the campaign's jobs go and its ledger header is tombstoned, results stay. The same teardown runs when aPATCHmoveskindaway fromcampaign.- Every route is yours only: another account's campaign id is
workflow_not_found, like a missing one.
Discover the pieces
The items a campaign processes still come from ordinary discovery — never guess an
agent id for the per-item work: plungeai_list_agents {search: "<what each item needs done>"} (REST: GET /v1/discovery/search?kind=agents&q=…). The ledger agent
data-table-agent is the exception: it is internal to the engine, has no discoverable card, and is
named only in the claim task of the campaign YAML.
The shape
campaignClaim— atype: taskleases up tobatch_sizepending items for this run.type: batchwithledger: campaign— fans out over the claimed items (items_from: claim,concurrency: N); each per-item task's success/failure is written back to the ledger automatically ascampaignComplete/campaignFail.- A campaign config tells the platform the list source, cycle
(
once/hourly/daily/weekly/monthly/continuous), cronschedule,max_attempts, and optional delivery/chaining: thecampaign_configJSON on REST and MCP, acampaign-configfenced block after the YAML in Studio.
workflow:
name: "Status-page watch"
tasks:
- type: task
id: claim
agent: data-table-agent
operation: campaignClaim
campaign_id: "<written at save>"
batch_size: 50
- type: batch
id: work
items_from: claim
concurrency: 5
ledger: campaign
tasks:
- type: task
id: one
agent: firecrawl-agent
operation: scrape
url: "{item.key}"
formats: [markdown]list: { inline: ["https://status.example-a.com", "https://status.example-b.com"] }
cycle: continuous
cycle_start: reset
schedule: "0 * * * *"
max_attempts: 3
deliver: [{ channel: slack }]Keeping it going
A campaign with a schedule in its config runs on an ordinary recurring cron job.
One WITHOUT a schedule ends its pipeline with agent: scheduler, operation: runAgain, in: "1h" — a self-scheduling @once job that never stacks. Both
mechanisms and full cron/date-token detail: plungeai-scheduling.
Gotchas
upsertRowis insert-only, not keyed — it does not matchmatchFields; usechainStepor explicitcol_<name>columns for an idempotent per-item write, orupdateRowsto change an existing row.- Never chain (
then) a dependent analysis report onto a data-collection campaign — a partial cycle must not trigger it; keep such reports time-triggered. - The scheduler's zero-progress breaker auto-pauses a campaign after several
consecutive runs that complete nothing — check
campaignStatusbefore assuming it needs a manual nudge. - Every ledger operation is scoped to the caller's own account — there is no cross-tenant campaign surface.
Related skills
plungeai-campaign-agent— the Studio kind that authors campaigns visually (kept id — this skill documents its underlying mechanics, not a replacement UI).plungeai-workflows— thebatch/task/harnesstypes a campaign pipeline is built from.plungeai-scheduling— cron cadence,@once, andrunAgainself-scheduling.plungeai-missions— when a per-item step needs judgment instead of a fixed call.plungeai-results-traces— reading a campaign run's execution history.
Reference
references/campaigns.md— thecampaign-configfield table, every ledger operation (campaignBegin/Claim/Complete/Fail/Release/Status/AddItems/RetryFailed/SetStatus/Delete/task rows/chainStep/counterStep), sizing, delivery channels, and gotchas.