For AI agents: a documentation index is available at https://www.plungeai.com/docs/llms.txt. Append .md to any page URL, or send Accept: text/markdown, to get markdown. Setup instructions for agents are at https://www.plungeai.com/docs/agents.md. One ozk_ key opens every plane, models included.

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

Source: orchestration/mcp-gateway/tools.ts (ExecuteWorkflowSchema, executeWorkflow, ListWorkflowsSchema, listWorkflows, WorkflowSchema, plungeaiWorkflow, BuildWorkflowSchema), orchestration/mcp-gateway/workflow-store.ts, orchestration/mcp-gateway/chat.ts (buildWorkflow), orchestration/mcp-gateway/extras.ts (plungeaiTemplates), orchestration/mcp-gateway/execution.ts (runExecution, executeViaStream), orchestration/mcp-gateway/execution-do.ts, orchestration/mcp-gateway/leg-state.ts, orchestration/mcp-gateway/tool-outcome.ts, orchestration/mcp-gateway/server.ts, orchestration/cnl-engine/cnl-engine.ts (loadWorkflow, request input / inputs), agents/agents/one-agent/call-config.ts, agents/agents/one-agent/call-mode.ts, core/core-base/provider-ids.ts, apps/ocean-skills/skills/plungeai-workflows/references/cnl-spec.md.

Your workflows are saved CNL workflows. CNL is the platform's YAML workflow language. Users call their workflows "my agents", and most day-to-day work is here: find a workflow, run it, inspect it. There is no separate "MCP workspace". A workflow you create or run here is the same workflow you see in Studio and the apps, and every change syncs live.

JobTool
Find your workflows and foldersplungeai_list_workflows (8.1)
Run a saved workflow, or ad-hoc YAMLplungeai_execute_workflow (8.2)
Create, read, edit, delete, versionplungeai_workflow (8.6)
Generate or refine one from plain languageplungeai_build_workflow (8.8)
Copy a ready-made template into your accountplungeai_templates use (8.9)

Base URL https://mcp.plungeai.com/v1. https://api.plungeai.com/v1/mcp is the same server; the REST twin is https://api.plungeai.com/docs#10-workflows-plane (opens in a new tab). Always pass user_request: for "show me all my agents in the finance folder", the arguments alone are just {folder: "Finance"} and lose the intent. Parameter types and limits are in the Tool reference.

8.1 Find your workflows — plungeai_list_workflows

You sendWhat comes back
nothing# Your Workflows (N most recent), then **Folders:** Finance (15) · Personal (23) · … (only folders that hold something, in your sidebar order), then a table of your 50 most recently updated workflows
folderWorkflows whose folder name contains this text (case-insensitive)
searchWorkflows whose name contains this text (case-insensitive). Descriptions are not searched
kindOnly that kind: workflow, agent, bot or campaign (exact)
folder + search + kindAll given must match
limit1 to 100 (default 50)
format: "json"{"workflows":[{"id","name","description","kind","folder"}]}

The table columns are Name, Kind (workflow, agent or bot), Folder, ID, Description, newest first. The ID is what plungeai_execute_workflow and plungeai_workflow take. With no match you get "No workflows matched. List without filters to see your folders." An empty account answers "No workflows found. Create one with plungeai_workflow or plungeai_build_workflow." The tool is read-only.

Try asking

  • "Show me all the workflows in my Finance folder."
  • "What folders do I have and how many workflows in each?" For example: Finance 15 · Personal 23 · Technology 11 · Business Strategy 14 · Blockchain 8.
  • "Find my workflow about due diligence." This searches your workflow names, so a workflow called "DD Memo" is not found by "due diligence". List the folder instead if the name is different.
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_list_workflows","arguments":{"user_request":"What folders do I have and how many workflows in each?"}}}'

"Category" and "folder" are different things. Your folders (Finance, Personal, …) hold your workflows. Categories are the registry's agent taxonomy (Discovery), where the finance one is called financials.

8.2 Run a workflow — plungeai_execute_workflow

ArgumentMeaning
workflow_idA saved workflow you own (the ID from 8.1)
workflow_yamlAd-hoc CNL, up to 256 KiB (8.3)
inputThe primary input, available as {input}
inputsNamed inputs {key: value}, available as {key}
modesync (default) or async (8.4)
formatmarkdown (default) or json

Send workflow_id or workflow_yaml. With neither you get needs_input ("Provide either workflow_yaml (ad-hoc CNL) or workflow_id (a saved workflow)."). If you send both, workflow_id is used and the YAML is ignored.

Saved workflows. The id must be a workflow on your account. An unknown id, or one owned by someone else, returns needs_input ("No saved workflow with id <id> on this account.") with a pointer to plungeai_list_workflows, and no run. The run is named after the saved workflow. Its title in Studio's sidebar is your input (or the inputs values, or your user_request), the same as a run started in Studio.

Try asking

  • "Run the Acquisition Scanner with Adobe as the input." This runs a saved workflow. Most finish in seconds, because the engine fans out over agents in parallel.
  • "Show me my workflows in the Finance folder, then run the Acquisition Scanner with Tesla as the input." One request, two steps. Your client lists the folder to find the workflow you meant, then runs it with your input.
  • "Run my Company Snapshot Research Brief with Apple as the input." The same pattern: swap in whichever workflow and company you mean.

This runs your workflow's agents (it costs credits and writes an execution; not run by the docs verifier):

curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_execute_workflow","arguments":{"user_request":"Run the Acquisition Scanner with Adobe as the input.","workflow_id":"<workflow id from plungeai_list_workflows>","input":"Adobe"}}}'

A saved workflow's agents are not re-checked by the gateway at run time. Only ad-hoc YAML goes through the active-only fence (8.3). If a saved workflow names an agent that is no longer deployed, the run fails in the engine and comes back unavailable ("registered but not deployed").

8.3 Ad-hoc CNL YAML

workflow_yaml runs CNL without saving it. The workflow: wrapper is optional: bare top-level name + tasks is accepted and wrapped for you (Form B in the CNL spec). This example needs jq to build the JSON. It runs three agents (it costs credits; not run by the docs verifier):

YAML=$(cat <<'CNL'
name: Quick brief
tasks:
  - type: parallel
    id: research
    subtasks:
      - id: web
        agent: brave-agent
        prompt: "{input} — latest news"
      - id: deep
        agent: tavily-agent
        prompt: "{input} — cited sources from the last 12 months"
  - id: brief
    agent: one-agent
    prompt: |
      Write a five-bullet brief on {input}.
      Brave: {data:web}
      Tavily: {data:deep}
CNL
)
jq -n --arg yaml "$YAML" '{jsonrpc:"2.0",id:1,method:"tools/call",params:{name:"plungeai_execute_workflow",arguments:{user_request:"Quick brief on Cloudflare Workers",workflow_yaml:$yaml,input:"Cloudflare Workers"}}}' |
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d @-

What the gateway does before the engine sees it (executeWorkflow):

  1. Parses the YAML. If it cannot be parsed, you get needs_input ("Your workflow_yaml could not be parsed. <parser message>"), and the message points only at your text. Valid YAML that is a bare scalar (a string, a number) or empty returns needs_input ("workflow_yaml must be a CNL mapping with a workflow: (or top-level name/tasks), not a bare value."). Nothing runs in either case. A top-level list is not caught here: it is wrapped and dispatched without the agent fence below, fails in the engine, and leaves a failed execution in your history. Always send a mapping with workflow: or top-level name/tasks.
  2. Fences the agents. The agent: ids of your tasks are checked against the registry, including inside subtasks, batch tasks and executors, plus a harness task's mission_ref (collectAgentIds). Unknown or not-status:active ids return unavailable, naming each offender ("No such agent: …", "Not permitted: … not status:active"). Nothing runs. Agents named elsewhere (a dynamic generator, debaters, judges, validators) are resolved by the engine when the run starts.
  3. Wraps and runs. Your input and inputs travel with the workflow and fill {input} and {key}. The run is named <YAML name> · <first three agents> (+N for more). After the run, the name is replaced by the agents that actually ran. Every run also carries user_context (your time zone and approximate place, taken from the request's network location), which the agent uses for local time and as the default time zone for a schedule.

The gateway does not run the CNL schema validator on ad-hoc YAML, and the engine records schema findings without blocking the run (its validation mode is record-only; cnl-engine.ts). A malformed document is dispatched and fails however its tasks fail, and that leaves a failed execution in your history. To check a document first, save it with plungeai_workflow create: that call runs the validator (yamlToCNL) and rejects errors such as Workflow name is required and must be a string or Type 'harness' requires a 'goal' string before anything is stored. Or let plungeai_build_workflow write the YAML.

Writing YAML by hand

  • Quote your colons. prompt: DD: memo breaks YAML. Write prompt: "DD: memo", or put long text in a block scalar (prompt: |). Never hard-wrap a value across lines. An invalid yaml failure comes back with exactly this tip.

  • Structured tool-agents take their card's fields as task fields, next to agent::

    - id: wx
      agent: weather-agent
      operation: forecast
      city: "Sun Valley,ID,US"
      units: imperial

    Watch for card fields that share a name with a CNL task field. location is one: on a task it means cloud or local (where the task runs). A weather task with location: "Sun Valley,ID,US" runs as ad-hoc YAML, because the field passes through to the agent, but the validator used by plungeai_workflow and plungeai_build_workflow rejects it (Invalid location: Sun Valley,ID,US. Must be 'cloud' or 'local'). In a saved workflow, use the weather card's alias city (as above) or lat/lon.

  • On a one-agent task, prefer provider: gemini or omit provider. Omitting it gives the default (gemini, model gemini-3.1-flash-lite, agents/agents/one-agent/call-config.ts). google is accepted and mapped to gemini by the provider resolver (core/core-base/provider-ids.ts), but one-agent then does not apply its default model (it does so only for an omitted or literal gemini provider), so pass model explicitly if you write google. Any other unknown provider is refused (Unsupported provider: <x>, Troubleshooting).

  • Take agent ids from a live search, never from memory: it is brave-agent, not brave-search (Discovery).

  • Outward operations are fenced here too. A task whose operation or action is send, pay, buy, transfer, … is refused by the engine as needs_approval (6.6). Nothing runs, and plungeai_continue cannot resume it: such a task runs only from Ocean Studio.

  • There is no schedule: field. Schedule a workflow with plungeai_schedule (Scheduling).

Easier still: describe the goal and let "build me a workflow that…" write the YAML for you (8.8).

8.4 Sync and async

Sync (the default) runs the workflow and streams live status while it works. The lines come from the engine's own task events, the same ones Studio's live view renders (executeViaStream):

⚙️ Agents working — 5/18 agents complete · ✓ brave-agent · 13 active (tavily-agent, exa-agent, serper-agent…)
✍️ Generating answer — 16/18 agents complete · 2 active (one-agent)
✍️ Writing (3516 chars) — …the answer as it is produced
⚙️ one-agent still working — 45s elapsed…
✅ Complete — 18 agents in 24.6s

A keepalive (⏳ Working — Ns elapsed) is sent every 15 seconds so the stream never goes idle. The feed goes out on notifications/progress when your client sent a progress token, otherwise on notifications/message. Whether it is displayed is up to your client; the work and the result are the same either way (4.6). A quiet client is not a stalled run: the run is visible in Studio's sidebar the whole time.

Async (mode: "async") returns at once with the execution id. The tool description suggests it for runs longer than about 3 minutes, and it is the way around Claude Desktop's roughly 4-minute cap on a single call:

Started execution `<execution id>` (async). Poll plungeai_get_workflow_status with this id, then fetch output with plungeai_get_result once completed. If the status reports ⏸ AWAITING USER APPROVAL or AWAITING USER, relay it to the user and continue with plungeai_continue.

---
execution: `<execution id>` — use this id for plungeai_get_result / plungeai_followup on this run.

An async run has no live feed. It is held by its own Durable Object in resumable ten-minute legs, so it survives your client disconnecting (7.9). Poll plungeai_get_workflow_status, then fetch plungeai_get_result (Runs, results & follow-ups). A running execution that stops heartbeating for 16 minutes is marked failed, with Interrupted (run did not complete). Rerun it, in the foreground if it is short.

8.5 What a run returns

OutcomeWhen
okThe final task's output, then the execution footer (summary: "Workflow completed."). If the final task stored nothing, the stored outputs of the individual tasks are joined under ## <task id> headings instead. An async start is also ok
needs_approval / needs_inputA task paused for approval or a question (⏸ AWAITING USER APPROVAL: … / ⏸ AWAITING USER: …). Continue with plungeai_continue after the user decides
needs_approval (no actions)A task's operation/action is on the engine floor list. Nothing ran, and it cannot be continued over MCP (6.6)
needs_inputNo workflow given, unknown saved id, unparseable YAML, or an agent rejected its inputs
unavailableAd-hoc YAML names an unknown or inactive agent, or an agent is not deployed
needs_connection / needs_api_keyA task hit a missing connected account or key at run time. Workflows have no pre-flight, so the answer names "the required service" (6.7)
errorA genuine failure with the real reason. A timeout suggests mode: "async"

Every outcome follows the vocabulary in 6.4.

Two failure shapes are specific to runs. If the engine reports success but nothing was stored, the run is failed: "Engine reported success but no result was stored (final_task: …). The agent likely failed in-band without storing output — check its own logs." If the final answer starts with a refusal marker (# ❌, Error: ), the run is failed with that text, never shown as a success.

A run whose final harness task ran out of turns is stored as incomplete and reported that way by plungeai_get_workflow_status, but only for async runs. A sync run's answer is ok, and the sync path stamps the outcome ok afterwards, replacing the incomplete mark (7.7).

Every run is visible everywhere. It appears in Studio's results sidebar and the ops dashboard. The title is your question, and the subtitle is the workflow plus the agents that actually ran, the same as a run started in Studio. The result is final Markdown (tables, headings, links). Ask for it "in full" if your client tends to summarize. plungeai_get_result adds a "Steps in this run" index for multi-task runs, so any step's full output is one ask away (Runs, results & follow-ups).

8.6 Manage saved workflows — plungeai_workflow

Direct edits to your saved workflows. The store is byte-compatible with Studio's (D1 yaml_workflows + KV workflow:{user}:{id}), and every write is ownership-checked. Create, update and delete are broadcast and sync live to Studio, iMini and the other apps. save_version and restore_version are not broadcast, so reload an open Studio editor after a restore (saving from a stale editor would overwrite the restored YAML).

actionNeedsOptionalDoesAnswers
createname, yamldescription, folder, kindValidates the CNL, saves, files into the folder"Created workflow <name> (<id>). Filed under <folder>. Synced to all apps." plus any validation warnings
getworkflow_id—Reads the saved definition# <name>, the description, and the YAML in a code block
updateworkflow_idname, description, yaml, folder, kindChanges only what you send. New YAML is validated first. Moving kind away from bot or campaign runs the same clean-up as delete for the old kind (below)"Updated workflow <id>. Synced to all apps." plus " Moved to folder <folder>." / " Kind set to <kind>."
deleteworkflow_id—Deletes the workflow (the D1 row and its live content). A bot also loses its memory namespace <you>:bot:<id> and its scheduler jobs; a campaign loses its scheduler jobs and its ledger is tombstoned"Deleted workflow <id>. Synced to all apps."
save_versionworkflow_idversion_descriptionSnapshots the current YAML as the next version (8.7)"Saved version V<n> (<version id>)."
list_versionsworkflow_id—Lists the snapshots, newest firstA Version / ID / When / Note table, or "No versions yet. Use action "save_version"."
get_versionworkflow_id, version_id—Reads one snapshot# V<n> and its YAML
restore_versionworkflow_id, version_id—Makes that snapshot live again"Restored — new version V<n>."
permissions_getworkflow_id (a saved bot)—Reads its permission classes, locks and spend caps, and effective: the preset each of the four classes (send, write, pay, delete) runs under, the stored one or else allowclasses, effective, locks, budget_usd_run, budget_usd_month, and the same as JSON
permissions_setworkflow_idclasses, locks, budget_usd_run, budget_usd_monthEach field present replaces the stored one; locks only for a team admin over the workflow (otherwise Error: … (lock_admin_required) and nothing is written)"Updated." and the new policy
filesworkflow_id—Lists the bot's persistent workspacea Path / Size / Type / Updated table
fileworkflow_id, path—Reads one workspace file, at most 5 MBthe bytes as a base64 block (larger: use the One API download route)
inboxworkflow_id—Reads the bot-to-bot messages queued for its next runa From / When / Message table
bindingsworkflow_id—Lists the paired chats bound to the bota Channel / Sender id table, or a note that bindings are not enabled yet
bind, unbindworkflow_id, channel, sender_id—Binds a chat you already paired to the bot, or releases ita confirmation, or Error: … (not_paired)
groups——Lists your bot groupsa Name / Members / ID table
group_setgroup, members (2–6 bot ids)—Creates the group, or replaces the members of the one with that name"Created" / "Updated group …"
group_delete, group_threadgroup—Deletes the group, or reads its shared threada confirmation, or the thread table

Validation. On create, and on update with yaml, the YAML goes through the engine's CNL validator (yamlToCNL) before anything is stored. An error rejects the call: "Workflow YAML failed CNL validation: <field>: <message>, …" (isError), and nothing is saved. Warnings (near-miss keys such as input on a task where prompt was meant) are appended as "⚠️ Validation warnings:" and do not block. The same check runs the save-time kind lint: memory_owner in the YAML is an error for every kind (memory tenancy comes from the executing user), and an agent or bot must be exactly one type: harness task whose allowed_tools (if set) include task_complete. The kind linted is the kind you pass, else the stored one on update. Hardcoded emails or UUIDs only warn. The validator checks the schema, not the agents. A saved workflow can name an inactive agent and fail only when it runs, so take ids from Discovery.

Folders. folder is matched against your folder names: an exact case-insensitive match, otherwise a unique partial match. A name that matches nothing creates that folder (it appears in Studio at once) and files the workflow into it, on create, update and templates use alike. A name that partially matches two or more folders is an error naming them ("…is ambiguous — it matched 2 folders: Sales East, Sales West. Use the full name."), and nothing is changed. folder: "none" (or "") on update moves the workflow out of its folder.

Kind. kind picks the sidebar section: workflow (Flows, the default), agent (Agents), bot (Bot agents) or campaign (a list worked through on a cycle). A campaign create takes campaign_config ({list, cycle, max_attempts, schedule?, deliver?, …}): the config is checked before anything is saved, then the ledger and the scheduler job are set up and the campaign id is written into the YAML. Without campaign_config the campaign is saved with a warning and no ledger.

Bot control. The bot actions work on a saved bot you own and use the same stores as Studio's bot settings and the One API's /v1/workflows/{id}/permissions, …/workspace-files, …/inbox, …/bindings and /v1/bot-groups; a refusal reads Error: <message> (<code>) with the One API's code. Bindings need the message gateway and groups need their table: until then they answer a plain "not enabled yet".

Errors. A missing required field answers "Error: <field> is required for action "<action>"" (isError). An id that does not exist or is not yours answers "Workflow not found." or "Version not found." (isError), except get, which returns a needs_input outcome ("Workflow <id> not found.") pointing at plungeai_list_workflows. The bot actions (permissions_get, files, inbox, bindings, …) answer Error: no saved workflow with that id for this account (workflow_not_found) instead.

Two things to know. update does not save a version first (the same as Studio), so run save_version before an edit you may want to undo. delete is a hard delete of the workflow. Your past executions of it stay in your history. The clean-up that follows is best effort and never fails the call: for a bot it wipes only the memory namespace <you>:bot:<id> (older bots; a bot saved without memory_owner uses the memory of whoever runs it, which a delete never touches) and deletes the bot's scheduler jobs; for a campaign it deletes the jobs and tombstones the ledger. Changing a saved row's kind away from bot or campaign with update runs the same clean-up for the old kind.

Try asking

  • "Show me my Acquisition Scanner workflow — what does it actually do?" The client finds its id with plungeai_list_workflows and fetches the definition with get, so you can see exactly what it runs (which agents, in what order) before you trust it with real input.
  • "Rename my Acquisition Scanner, move it to the Finance folder, and save a version first." The client runs save_version, then update with name and folder.
  • "Create a workflow from this YAML and put it in Finance." create files it straight into the folder; no separate move is needed.
  • "What is my Outreach bot allowed to do without asking?" The client runs permissions_get; "Make it ask before sending anything" is permissions_set with classes: {"send": "ask"}.
  • "Group my Outreach and Research bots as Sales." group_set with group: "Sales" and the two bot ids; group_thread reads what they said to each other.

Reading a definition (read-only; it needs a real id, so it has no verifier marker):

curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_workflow","arguments":{"user_request":"Show me my Acquisition Scanner workflow","action":"get","workflow_id":"<workflow id>"}}}'

Creating one into a folder changes your account (not run by the docs verifier):

curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_workflow","arguments":{"user_request":"Save this as News Scan in my Finance folder","action":"create","name":"News Scan","folder":"Finance","description":"Latest news on a company","yaml":"name: News Scan\ntasks:\n  - id: news\n    agent: brave-agent\n    prompt: \"{input} latest news\"\n"}}}'

Reading a bot's policy is read-only (it needs a real id, so it has no verifier marker); permissions_set takes the same arguments plus the fields to change and writes them, and bindings, files, inbox and groups read the bot's paired chats, workspace, queued messages and groups the same way:

curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_workflow","arguments":{"user_request":"What is my Outreach bot allowed to do","action":"permissions_get","workflow_id":"<bot id>"}}}'

Creating a bot group changes your account (not run by the docs verifier):

curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_workflow","arguments":{"user_request":"Group my Outreach and Research bots as Sales","action":"group_set","group":"Sales","members":["<bot id>","<bot id>"]}}}'

The same workflow is also readable as the resource plungeai://workflows/{id} (Prompts & resources).

A2A doors

Every bot, agentic agent and workflow can get an Agent2Agent (A2A 1.0) door: a URL under https://a2a.plungeai.com/<handle> with its own bearer token, through which any A2A client — another vendor's agent, the official a2a-sdk clients, or one of your own bots — sends it work. plungeai_workflow action: "a2a_door" manages it: door_action: "mint" creates the door and shows the token once (minting again rotates it), get shows the door, pause / resume close and reopen it, revoke deletes it. The door's agent card is at <door url>/.well-known/agent-card.json; a SendMessage runs the workflow as you and returns the result as a text artifact (bots and agentic agents continue the conversation when the caller reuses the contextId; a session that stops with a question answers TASK_STATE_INPUT_REQUIRED). Long work: send with returnImmediately or stream, then poll GetTask. A bot reaches another A2A agent with message_bot and a peers entry a2a:<url>; its bearer for that agent is the Connections credential a2a:<host> (or a2a:<host>/<path> for one door on a host).

8.7 Versions

Versions are explicit snapshots (workflow-store.ts):

  • save_version copies the current live YAML into a new version numbered one above the highest so far (V1, V2, …), with an optional version_description note and a checksum. It becomes the workflow's current version.
  • list_versions shows every snapshot: Version, ID (the version_id), When (ISO time), Note.
  • get_version returns one snapshot's YAML without changing anything.
  • restore_version writes that snapshot's YAML back as the live definition, then saves it as a new version with the note "Restored from V<n>". History is never rewritten, and you can always roll forward again.

update and plungeai_build_workflow's refine both overwrite the live YAML without a snapshot. Save a version first so you can roll back.

8.8 Generate a workflow — plungeai_build_workflow

plungeai_build_workflow turns a plain-language goal into a real multi-agent workflow and saves it. It uses the platform's workflow builder, which picks actual registry agents, validates the YAML and repairs it itself.

You sendDoes
goalGenerates a new workflow and saves it. It is named from the generated YAML's own name: line (up to 120 characters), or from the first 60 characters of your goal when the YAML has no plain name: value line (a name containing a quote or apostrophe does not count as one), with the description "Generated via MCP builder", no folder, kind workflow
workflow_id + instructionRefines an existing workflow: sends its current YAML plus your change to the builder, which regenerates the whole workflow, then overwrites it in place. The name stays; no version is saved
anything else"Provide either goal (new) or workflow_id + instruction (refine)." (isError)

If you send goal together with workflow_id but no instruction, a new workflow is generated and the id is ignored.

It takes 30 to 60 seconds, and it narrates while it works:

📖 Loading the existing workflow…                (refine only)
🧠 Generating CNL YAML — the builder picks real agents, validates and self-repairs (30-60s)…
🔍 Validating the generated workflow (2,431 chars)…
💾 Saving "Acquisition News Briefing" and syncing to all apps…
✅ Complete

The answer names the workflow and its id, says "Synced to all apps.", and, for a new one, "Run it with plungeai_execute_workflow.", followed by the full YAML in a code block. It fails with isError and saves nothing when:

  • the workflow id is unknown ("Workflow not found: <id>");
  • the builder returns no workflow ("Workflow builder did not return a workflow section.");
  • the generated YAML fails CNL validation ("Generated workflow failed CNL validation: …", with the YAML attached so you can fix it by hand).

The tool has no format argument.

Try asking: "Build me a workflow that scans a company for acquisition news and writes a briefing." To file it, follow up with "…and move it to Finance" (plungeai_workflow update with folder). To design a workflow in a conversation first, "Let's design a due-diligence workflow together" goes to plungeai_chat (Chat, memory & skills).

This runs the builder model and saves a workflow (it costs credits; not run by the docs verifier):

curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_build_workflow","arguments":{"user_request":"Build me a workflow that scans a company for acquisition news and writes a briefing.","goal":"Scan a company (given as input) for recent acquisition news from several web sources in parallel, then write a one-page briefing with sources."}}}'

To refine: {"workflow_id":"<id>","instruction":"Add a step that checks SEC filings for the same company."}. Run save_version first.

8.9 Start from a template — plungeai_templates use

use copies a template (5.5) into your account as a new workflow you can edit:

  • The name is your name, otherwise "<template name> (copy)". A bot template keeps its own name.
  • The template's kind (agent or bot) and its description carry over.
  • folder files it with the same matching as plungeai_workflow create: no match means the workflow is created without a folder, with a ⚠️ note listing your folders.
  • The template's usage count goes up by one, the same as in Studio.
  • The YAML is copied as it is. It is not re-validated.

The answer: "Created workflow <name> (<id>) from template <template>. Filed under <folder>. Run it with plungeai_execute_workflow."

Try asking: "What workflow templates are available? Start one from the due-diligence template."

This creates a workflow in your account (not run by the docs verifier):

curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_templates","arguments":{"user_request":"Start one from the due-diligence template","action":"use","template_id":"<template id from list>","name":"Due Diligence — Acme","folder":"Finance"}}}'

8.10 CNL essentials for ad-hoc YAML

The full language reference is the plungeai-workflows skill (https://skills.plungeai.com (opens in a new tab)). The same guide is served to your client as the plungeai://docs/workflow-authoring resource (Prompts & resources). It is also summarised at https://api.plungeai.com/docs#101-cnl-in-one-page (opens in a new tab). The short version (cnl-spec.md, engine v6):

  • Shape. workflow: {name, tasks, inputs?} (Form A) or bare name + tasks at the top level (Form B). Both are accepted. The spec's Form B top-level input: is not read over MCP: the gateway nests the whole Form B document under workflow:, where nothing reads input. Pass the value as the tool's input argument instead, or declare inputs: inside a Form A workflow: block.
  • Ten task types. task (one agent: agent + prompt or query), parallel and sequential (subtasks), dynamic (generator + executors), batch (tasks over items / items_from), output, debate, validate, agent_loop (legacy), harness (a mission: goal + mission or mission_ref).
  • Interpolation. {input}, {key} from inputs, {data:task_id} for a prior task's result, {item} / {item.field} inside a batch.
  • Hard rules. Agent ids exactly as in the registry. No $variable, depends_on, outputs: or parallel: true. Container blocks never carry agent:. type: task reads prompt:, not input or instructions. Unique ids.

A mission as YAML: a type: harness task with the full mission fields, including experts, plugins, MCP servers, effort, spend cap and permissions, which plungeai_run_mission does not expose (7.7):

name: Vendor scan
tasks:
  - 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
      allowed_tools: [web_search, web_fetch, task_complete]
      success_criteria:
        - "5 vendors named with pricing"
        - "every claim has a source URL"

Run it with plungeai_execute_workflow, passing the YAML as workflow_yaml and the value for {input} as the tool's input argument (for example "input":"workflow orchestration platforms").

Planned: TI-34

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