For AI agents: a documentation index is available at https://docs.plungeai.com/llms.txt. Append .md to any page URL, or send Accept: text/markdown, to get markdown. Setup instructions for agents are at https://docs.plungeai.com/agents.md. Execution planes take an ozk_ key; the models plane takes an sk-ocean- key.

Documentation Index: fetch the complete documentation index at /llms.txt. Use this file to discover all available pages before exploring further.

A campaign-config fenced block sits after the CNL YAML. Studio parses it to open the ledger and create the scheduler job. Fields:

FieldRequiredMeaning
listyesWhere items come from. One of table: (a data-table project+table), agent: (a lister task whose JSON array feeds items_from), csv: true (uploaded rows), or inline: [key, …].
cycleyesCalendar bucket: once | hourly | daily | weekly | monthly | continuous.
cycle_startwhen re-listingrefill (add new list rows, keep prior) or reset (fresh cycle from the list).
scheduleyesCron for the run cadence, e.g. "*/5 9 * * 1". The scheduler re-fires until the cycle drains.
max_attemptsyesPer-item retry cap before an item is marked failed (integer ≥ 1; the ledger column defaults to 2).
thennoCampaign id to hand the baton to when this one's cycle completes.
delivernoChannels for the cycle-complete notice (see below).
localnotrue runs items on the user's own computer.
max_itemsnoHard cap on total items claimed across the cycle.
task_typesnoPer-row task/worker overrides (§8a).
learnnoEnables the ledger's recall/knowledge lane (§8a–8c).

Sizing (rule of thumb)

Keep batch_size × seconds per item ÷ concurrency ≤ 600 s — well inside the 15-minute DO wall. The default batch_size: 40, concurrency: 5 at ~30 s/item = 4 min per run; up to ~100 items per run is safe on the scheduled path. batch_size and concurrency are hidden authoring knobs — never operator vocabulary.

deliver channels

  • Fire-and-forget: a delivery failure never fails the run.
  • Length caps per channel: telegram 3800, whatsapp 3800, discord 1900, slack 3800, email 100000, inapp 2000 characters — keep the bot's output well under the smallest cap you use.
  • telegram / whatsapp targets must be paired to the owner: generate a pairing code in Studio and send /pair <code> from that chat (Telegram additionally requires the user to have opened the bot once); discord requires any active pairing. Unpaired targets are skipped.
  • email sends from the platform address; a bare email target means the owner's address. Any other address delivers only after that address holder confirmed it (a confirmed delivery recipient) — otherwise the target is skipped silently.
  • slack: a bare target DMs the owner; a chat_id / to target needs the owner to be a connected workspace member.

Worked shapes

1 · Weekly catalog price check (the Arhaus case)

280 active products, ~30 s each, concurrency 5, 40 per run → seven runs of ~4 min on Monday morning, exhausted by ~09:34; analysis (10:00) and Excel (10:15) stay separate time-triggered jobs.

workflow:
  name: "RH price check"
  description: "Weekly price check of the tracked catalog"
  tasks:
    - type: task
      id: claim
      agent: data-table-agent
      operation: campaignClaim
      campaign_id: "<written by Step-2 at save>"
      batch_size: 40
    - type: batch
      id: work
      items_from: claim
      concurrency: 5
      ledger: campaign
      tasks:
        - type: task
          id: one
          agent: price-collector-v2-agent
          operation: collect_single
          product_name: "{item.key}"
          week_date: "{item.cycle}"
list:
  table: { project: furniture-pricing, table: products, filter: { status: active }, key: product_id }
cycle: weekly
cycle_start: refill
schedule: "*/5 9 * * 1"
max_attempts: 2
deliver: [{ channel: inapp }]
local: false

2 · 200 leads, enriched once

A CSV uploaded in the Task app; a small harness per item; runs every five minutes until exhausted (~5 runs), then done: job paused, summary delivered.

workflow:
  name: "Lead enrichment — September list"
  description: "Enrich each lead once and store the result"
  tasks:
    - type: task
      id: claim
      agent: data-table-agent
      operation: campaignClaim
      campaign_id: "<written by Step-2 at save>"
      batch_size: 40
    - type: batch
      id: work
      items_from: claim
      concurrency: 5
      ledger: campaign
      tasks:
        - type: harness
          id: one
          goal: "Enrich the lead {item.key} ({item.company}, {item.email}). Find the company's website, size and industry; store the result with call_agent to data-table-agent, upserting by key {item.key} in cycle {item.cycle}."
          mission: |
            You are a lead researcher. Use only public sources and cite the URL you relied on.
            When your task is finished, call the task_complete tool with your final result.
          effort: quick
          allowed_tools: [web_search, web_fetch, call_agent, task_complete]
          allowed_agents: [data-table-agent]
list:
  csv: true
cycle: once
cycle_start: reset
schedule: "*/5 * * * *"
max_attempts: 2
deliver: [{ channel: inapp }, { channel: email }]
local: false

3 · Continuous monitor of 50 URLs

An inline list; each exhaustion opens the next cycle (#n+1). The no-progress breaker (three consecutive runs completing nothing) pauses an all-failing list instead of looping on it.

workflow:
  name: "Status-page watch"
  description: "Check 50 status pages continuously and record changes"
  tasks:
    - type: task
      id: claim
      agent: data-table-agent
      operation: campaignClaim
      campaign_id: "<written by Step-2 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 }]
local: false

4 · Chain: finish list A, then start campaign B

Campaign A runs once; when its cycle completes, the scheduler sets campaign B's job to run now. Never use this to chain a dependent report onto a data-collection campaign — a partial cycle must not trigger analysis on incomplete data (the Arhaus analysis/Excel jobs stay time-triggered for exactly this reason).

list:
  agent: { id: registry-sync-agent, operation: list_stale_cards }
cycle: once
cycle_start: refill
schedule: "*/5 * * * *"
max_attempts: 2
then: "<campaign B id>"
deliver: [{ channel: inapp }]
local: false

Planned: TI-33

Search is not available yet. Until it ships, use the page index or browse the sidebar.

Planned: TI-34

The docs assistant is not available yet. You can hand these docs to your own assistant instead.