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.

CNL (Cognitive Natural Language) is PlungeAI's YAML workflow language: you declare tasks and how they compose (parallel, sequential, batch, debate, harness, …), and the engine dispatches them to platform agents with automatic data flow between steps. This reference is generated for engine v6 and is mechanically drift-checked against the engine source — trust it over older docs.

Workflow shape (choose ONE)

Form A — wrapped

workflow:
  name: string              # required
  version: "1.0.0"          # optional
  description: string       # optional
  inputs:                   # optional — named variables, accessible as {key}
    key: value
  tasks: [Task]             # required, ≥1

Form B — flat

name: string
version: "1.0.0"
description: string
tasks: [Task]
input: string               # optional single-input (backwards-compat), accessible as {input}

Both forms are accepted everywhere (ad-hoc execution auto-wraps Form B). A followup: block may exist in saved workflows but is ignored by the engine.

Fields every task may carry: id (unique string — needed if later tasks reference its result), type (defaults to task), description, condition (CEL expression evaluated BEFORE dispatch; task is skipped when false), location: cloud | local (default cloud; local routes to the user's connected desktop daemon).

Task types (10)

task — single agent call

Required: agent (kebab-case registry id) plus prompt (AI agents) OR query (search agents). All three must be strings when present. Optional: retry: 0-2 — re-dispatches the same task on failure. Idempotency warning: a retry re-fires the FULL agent call; if the agent's side effect (payment, message send, external mutation) completed before the failure was reported, the retry duplicates it. Set retry only on read-only/idempotent agents; leave it 0 for payment-, messaging-, and automation-class agents. Retry applies ONLY to plain task — never to harness. Agent-specific fields pass through untouched (e.g. operationType for exa-agent, max_results for search agents, provider/model for llm-agent, digital_twin — legacy alias persona — for skill-agent). Do NOT put subtasks on a task. These near-miss keys are warned as mistakes: input, instructions, instruction, message (you meant prompt) and goal (belongs to harness).

- type: "task"
  id: "research"
  agent: brave-agent
  prompt: "{input} — latest developments"

parallel — concurrent execution

Required: subtasks: [Task] with ≥1 entry (tasks: is an accepted alias for subtasks:). ALL subtasks dispatch at once. The block itself must not carry agent/prompt/query — those belong on subtasks.

sequential — serial with data chaining

Required: subtasks: [Task] with ≥1 entry (tasks: alias accepted). Each task automatically receives the previous task's output, and any prior task's result is addressable as {data:task_id}. The block itself must not carry agent/prompt/query.

dynamic — generator + executors

Required: generator: { agent, prompt? } (agent string required) and executors: [{ agent }] (≥1, each with an agent string). Optional: max — positive integer cap on generated items. The generator produces a list; each executor runs per item. No subtasks here, and no root-level agent/prompt/query.

- type: "dynamic"
  id: "fanout"
  generator: { agent: llm-agent, prompt: "List the top competitors of {input}, one per line" }
  executors:
    - agent: brave-agent
  max: 5

batch — per-item pipeline over a list

Required: tasks: [Task] (≥1 — the per-item pipeline; batch uses tasks, not subtasks) and either items: [...] (non-empty static list of strings or objects) or items_from: "task_id" (a prior task's result provides the list). Optional: track: true — persists per-item status and resumes completed items on re-run (off by default). Inside the pipeline, {item} is the current item (objects are JSON-stringified) and {item.field} addresses object fields. Data chains automatically between the pipeline's tasks — write follow-up prompts against the flowing data (e.g. "Summarize the research above for {item}"), not {data:...} (per-item task ids are rewritten internally). No generator/executors here — that's dynamic.

output — final delivery

Optional: format: html | text | markdown. The source content is auto-resolved from the flowing data; other fields are agent-specific. Use as the last task to shape the deliverable.

debate — multi-perspective reasoning

Required: debaters: [{ agent, position?, digital_twin? }] with ≥2 debaters (each needs an agent string; legacy alias persona). Optional: judge: { agent, prompt? } (agent string required when present), rounds: 1-5 (integer, default 1). No subtasks/generator/executors/items on a debate.

validate — consensus / majority / pass-fail (MACRO)

Required: validators: [{ agent, validation_rule? }] (≥1, each with an agent string). Optional: aggregation: consensus | majority | all_pass | any_pass (default consensus), success_criteria: string (injected into all validator prompts). This is a macro: the engine expands it into a parallel block of PASS/FAIL validator tasks plus one judge task (<id>_verdict) carrying the aggregation rule. The hand-written expanded form is equally valid. No subtasks/generator/executors/items.

agent_loop — legacy bounded loop

Exists for backwards compatibility; dispatches to the loop runtime with a recursion depth guard. Prefer type: harness — it is the supported, validated form of the same idea.

harness — mission-bounded agent run (the flagship)

One goal-driven run of the loop runtime (default harness-agent; agent: optionally overrides the runtime). Use ONE harness task for open-ended work instead of many small tasks.

Required:

  • goal — the per-run input, a string (prompt: is an accepted authoring alias and is folded into goal).
  • A mission, in one of three forms:
    1. inline purpose text: mission: "You are a market analyst. Stay on topic." (any string with whitespace)
    2. inline object (fields below)
    3. a pre-built agent card reference: mission_ref: card-id (alias pack:, or a single-token mission: value). If BOTH a card ref and an inline object are set, the inline values override the card per key (the engine warns).

Inline mission object fields (all optional except mission):

FieldMeaning
missionStanding purpose → system-prompt frame (required in object form)
personaPersona / digital-twin id — one voice per run (single string)
skillsSkill ids, array — injected eagerly (budget-capped), rest loadable in-loop
expertsExpert/specialist ids, array — labeled context sections
backgroundsAlways-on ambient context card ids, array
pluginsPlugin bundle ids, array — expand to skills + mcp + scripts
mcpMCP server ids, array — connected in-loop
model / providerModel/provider override
effortquick | standard | deep — turn/parallel budget preset
python_executorauto | pyodide | anthropic | gemini — run_python routing
instructionsExtra instructions appended after skills
allowed_toolsTool fence, array — only these reach the LLM; omitted → fail-closed default fence
allowed_agentsAgent fence for call_agent: array of ids, or 'all'
denied_agentsArray — subtracted from allowed_agents: all
success_criteriaArray of self-checked statements
max_turnsLoop turn cap, positive number (max_iterations is a legacy alias; optional — effort/agent default applies when absent)
max_parallelWidest fan-out one delegate call may spawn (cap-and-refuse)
max_tokensPer-turn OUTPUT token budget for the loop's model calls (runtime default 16384)
budget_usd_runPer-run spend cap in USD — the loop prices its running token cost each turn and stops (stopReason: 'budget') once it exceeds this; absent = no cap
permissionsMap of tool → allow | ask | deny (ask pauses the run for human approval)
permission_locksAdmin-locked permission classes, array — a class listed here forces its allow up to ask so a bot author's own allow cannot silently auto-run it; sourced from the Studio execute boundary, never trusted from raw YAML for enforcement
memory_ownerMemory namespace override — do not use; omit entirely (policy 2026-08-23). Never put a user id in YAML: ownership lives on the workflow row and runtime identity is injected per run; a hardcoded id that isn't the runner's own is rejected by the harness guard anyway. See orchestration/BOT-CREATION.md.
localtrue = this run's actions execute on the user's own computer via the desktop daemon (cloud brain, local hands; requires a connected local node)
local_agentsWhich local agents may be used (array; absent + local: true → all connected)

Mission fields may also be written FLAT on the task (peers of goal:) — the engine folds them into the mission. Validation errors you'd hit: missing/non-string goal ("Type 'harness' requires a 'goal' string"), no mission or card ("requires a 'mission' … or a 'mission_ref'"), object mission without a purpose string, non-array allowed_tools, non-positive max_turns, effort outside quick/standard/deep, capability fields (skills/experts/backgrounds/plugins/mcp) not arrays of strings, persona not a single string.

- type: "harness"
  id: "market_scan"
  goal: "Map the top 5 vendors for {input}, with pricing and one differentiator each."
  mission:
    mission: "You are a market analyst. Research thoroughly, cite sources, stay on topic."
    effort: "standard"
    max_turns: 12
    success_criteria:
      - "5 vendors named with pricing"
      - "every claim has a source URL"

Interpolation

  • {input} — the primary input (input: at the workflow level, or the input given at execution)
  • {key} — any named variable declared in inputs:
  • {data:task_id} — result of a prior task by id
  • {item} / {item.field} — current item inside a batch pipeline

Data flows automatically between sequential tasks — don't hand-wire results.

Hard rules

  • Agent names MUST match the live registry exactly (kebab-case) — discover them via registry search, never from memory. Do NOT use brave-search — use brave-agent. Execution refuses unknown or inactive agent ids.
  • Never use $variable, depends_on, outputs:, or parallel: true — these don't exist.
  • parallel / sequential / batch / dynamic / debate / validate blocks MUST NOT carry an agent field directly — agents go on the inner tasks.
  • type: task reads prompt: (or query:) — not input, instructions, instruction, or message. goal belongs to type: harness only. subtasks never belongs on a task.
  • Every id must be unique within its scope.
  • Long prompts use YAML block scalars (prompt: |) — never hard-wrap a value; quote values containing colons.
  • digital_twin: (legacy alias persona:) only works on skill-agent and on debater/validator/judge entries.
  • Nesting is unlimited: parallel inside sequential inside parallel, etc. Keep it under ~4 levels for sanity.
  • Scheduling is configured in the platform (Studio), not in YAML — there is no schedule: field.

Validation errors you may see

Message (verbatim)Fix
Workflow name is required and must be a stringAdd a top-level name:
Workflow must have at least one taskAdd a tasks: list
Invalid task type: X. Must be 'task', 'parallel', 'sequential', 'dynamic', 'batch', 'output', 'debate', 'validate', 'agent_loop', or 'harness'Use one of the 10 types (or omit type: for a plain task)
Type 'harness' requires a 'goal' stringAdd goal: (or prompt: alias) to the harness task
Type 'harness' requires a 'mission' (purpose text or inline object) or a 'mission_ref' (pre-built agent card id)Add a mission — text, object, or card ref
Type 'parallel' requires a subtasks arrayPut the inner tasks under subtasks:
Type 'dynamic' requires a generator object with at least an 'agent' fieldAdd generator: { agent: ... }
Type 'batch' requires either 'items' (array) or 'items_from' (task ID string)Provide the item source
Type 'debate' requires at least 2 debatersAdd a second debater
Rounds must be a positive integer between 1 and 5Fix rounds:
Aggregation must be one of: consensus, majority, all_pass, any_passFix aggregation:
Type 'task' does not read 'input' — did you mean 'prompt'? (warning)Rename the field to prompt:
Type 'task' should not have subtasks (use 'parallel' or 'sequential') (warning)Change the type or move subtasks
Max must be a positive integerFix max: on the dynamic block

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.