> ## Documentation Index
> Fetch the complete documentation index at: https://docs.plungeai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflows — execute_workflow, get_workflow_status, list_workflows, workflow, build_workflow, executions

> Workflows are CNL YAML run by the platform engine.


<!-- sources-of-truth: orchestration/mcp-gateway/tools.ts, orchestration/mcp-gateway/server.ts, orchestration/mcp-gateway/chat.ts, orchestration/mcp-gateway/workflow-store.ts, orchestration/mcp-gateway/conversation.ts, orchestration/mcp-gateway/extras.ts | last-synced: 2026-09-24 (added the plungeai_templates "use" action — list/get live in plungeai-discovery) -->
Workflows are CNL YAML run by the platform engine. Authoring guidance (task
types, recipes, validation rules) lives in this **plungeai-workflows** skill —
this file covers the MCP tools that run, manage, and observe them. Everything
these tools create syncs live to Studio and peer apps (one account, same
data, every surface).

---

## plungeai_execute_workflow

**Purpose:** execute a CNL workflow — either a saved one (`workflow_id`) or
ad-hoc YAML (`workflow_yaml`). One of the two is required.

**Parameters**

| Param | Type | Notes |
|---|---|---|
| `workflow_yaml` | string ≤256 KiB | Ad-hoc CNL. The `workflow:` wrapper is optional — bare top-level `name:`/`tasks:` is wrapped automatically. |
| `workflow_id` | string | A saved workflow the caller owns (from `plungeai_list_workflows`). |
| `input` | string ≤65536 | Fills `{input}` placeholders; also becomes the run's display title. |
| `inputs` | map string→string (values ≤8192) | Named inputs for multi-input workflows. |
| `mode` | `sync` \| `async` | Sync (default) streams progress and returns the result. Async returns an `execution_id` immediately — use for runs that could exceed ~3 minutes. |

**Example (ad-hoc, sync)**

```json
{"user_request": "get me the latest AI news",
 "workflow_yaml": "name: quick\ntasks:\n  - agent: brave-agent\n    prompt: \"{input}\"\n",
 "input": "latest AI news"}
```

**Example (saved, async)**

```json
{"user_request": "run my due diligence workflow on Acme",
 "workflow_id": "wf-1234...", "input": "Acme Corp", "mode": "async"}
```

**Returns:** an outcome envelope. Sync `ok` → the final output + execution-id
footer; a paused run → `needs_approval`/`needs_input` with the ⏸ block.
Async → "Started execution `<id>` (async). Poll plungeai_get_workflow_status
..., then fetch output with plungeai_get_result. If the status reports
⏸ AWAITING USER APPROVAL or AWAITING USER, relay it to the user and continue
with plungeai_continue." — follow that script literally.

**Failures & fixes**

- Neither `workflow_yaml` nor `workflow_id` → `needs_input`; provide one.
- "No saved workflow with id ... on this account." → list with
  `plungeai_list_workflows` and use a real id (ownership is enforced).
- Ad-hoc YAML naming an unknown/inactive agent → `unavailable` refusal
  BEFORE dispatch (the fence walks nested `parallel`/`sequential` blocks
  too). Re-discover the agent id; a refusal writes no execution row.
- "Invalid YAML" → the envelope carries a repair tip: quote any value
  containing a colon (`prompt: "DD: memo"`), write long strings as block
  scalars (`prompt: |`) and never hard-wrap a value — or compose with
  `plungeai_build_workflow` instead.
- Timeout in sync mode → remediation says `retry_with {mode: "async"}`; do
  that rather than re-running sync.

---

## plungeai_get_workflow_status

**Purpose:** check one of the caller's executions. Self-heals stuck rows: a
"running" row whose result already landed flips to `completed`; a run silent
for over 15 minutes flips to `failed` ("Interrupted") — so a dead async run
never reads "running" forever. Read-only.

**Parameters:** `execution_id` (required). Engine ids (`exec-...`, hyphen)
resolve too; scheduler run ids (`exec_...`, underscore) are redirected to
`plungeai_schedule {action: "runs"}`.

**Example**

```json
{"user_request": "is my report done yet?", "execution_id": "d3adb33f-..."}
```

**Returns:** markdown (workflow, status, error if failed, started, duration,
final task) plus `structuredContent` a machine mirror:

```json
{"execution_id": "...", "status": "running|completed|failed",
 "error_message": null, "workflow_name": "...", "started_at": "...",
 "duration_ms": 1234, "final_task_id": "...",
 "continuation": {"status": "needs_approval", "agent": "...",
                   "question": null, "pending_action": {"summary": "...", "price": "..."}}}
```

`continuation` is non-null when the run is PAUSED awaiting the user (async
pollers meet approvals here first). Its `status` is one of two values:
`"needs_approval"` (the ⏸ AWAITING USER APPROVAL block; `pending_action`
carries the summary/price) or `"question"` (the ⏸ AWAITING USER block;
`question` carries the text). Either way: relay it and use
`plungeai_continue`. `status: completed` → fetch output with
`plungeai_get_result`. Full conversation/HITL protocol: `plungeai-results-traces`.

**Failures & fixes:** "No execution found for ID" → wrong/foreign id (take it
from a footer or the executions list). "Status storage is temporarily
unavailable" → transient, retry in a moment.

**Polling etiquette:** poll every few seconds for short runs, backing off for
missions; stop on `completed`/`failed` or a non-null `continuation`.

---

## plungeai_list_workflows

**Purpose:** the user's SAVED workflows — what users usually mean by "my
agents". Read-only.

**Parameters:** `search` (name contains), `folder` (folder name contains),
`limit` (1–100, default 50).

**Behavior:** with no filters, the answer opens with a folder overview
(non-empty folders only, with counts) and a recency-ordered table — Name,
Kind (`workflow`/`agent`/`bot`), Folder, ID, Description. With filters, just
the matching table.

**Example:** `{"user_request": "show my agents in the finance folder", "folder": "Finance"}`

**Failures & fixes:** "No workflows found." → offer `plungeai_workflow
{action: "create"}`, `plungeai_build_workflow`, or `plungeai_templates`. "No
workflows matched." → list without filters to see real folder names.

---

## plungeai_workflow (CRUD + versioning)

**Purpose:** manage saved workflows directly. Every write syncs live to
Studio and peer apps.

**Actions & required params**

| Action | Requires | Notes |
|---|---|---|
| `create` | `name`, `yaml` | Server-side CNL validation first — a refusal lists field errors; fix exactly those. Optional `description`, `folder` (filed via create-then-move), `kind` (`workflow` \| `agent` \| `bot` — the sidebar section). |
| `get` | `workflow_id` | Returns name, description, and the full YAML block. |
| `update` | `workflow_id` | Any of `name`, `description`, `yaml` (re-validated), `folder` (move; `"none"` or `""` clears), `kind`. |
| `delete` | `workflow_id` | Removes it everywhere. |
| `save_version` | `workflow_id` | Snapshot (optional `version_description`) — do this before big edits. |
| `list_versions` | `workflow_id` | Version table (V#, id, when, note). |
| `get_version` | `workflow_id`, `version_id` | That version's YAML. |
| `restore_version` | `workflow_id`, `version_id` | Restores as a NEW version. |

**Example**

```json
{"user_request": "save this as a workflow called Daily Brief",
 "action": "create", "name": "Daily Brief",
 "yaml": "name: daily-brief\ntasks:\n  - agent: brave-agent\n    prompt: \"{input}\"\n",
 "description": "Morning news brief", "folder": "News"}
```

**Failures & fixes:** "Workflow YAML failed CNL validation: <field errors>" →
fix exactly the named fields (see this skill's CNL rules), retry once.
"Workflow not found." → not this user's id — re-list.
Folder misses split by action: on **create** the miss is non-fatal (⚠️ "…
created without a folder." — fix later with `update`); on **update** a folder
miss FAILS the whole update — `No folder matched "<name>". Your folders:
&lt;list>` — and NONE of the other patch fields (name/yaml/kind/description) are
applied. The error lists your real folder names: pick one and re-send the
full update. Validation ⚠️ warnings are non-fatal — surface them.

---

## plungeai_build_workflow

**Purpose:** have the platform builder generate (or refine) a workflow from
natural language. It picks REAL registry agents, validates, self-repairs, and
saves — the fastest correct path when the user describes an outcome rather
than YAML.

**Parameters:** either `goal` (new workflow) or `workflow_id` + `instruction`
(regenerate an existing one with a change applied).

**Example:** `{"user_request": "build me a workflow that researches a company and drafts an outreach email", "goal": "Research a company from its name, then draft a personalized outreach email"}`

**Returns:** "Created workflow **<name>** (`<id>`). Synced to all apps. Run
it with plungeai_execute_workflow." plus the full generated YAML. Expect
30–60s (a single generation call with an internal self-repair loop) —
progress notifications cover the wait; don't re-call mid-generation.

**Failures & fixes:** "Generated workflow failed CNL validation: ..." (rare —
includes the YAML) → retry once with a sharper goal, or hand-fix the YAML
and save via `plungeai_workflow {action: "create"}`. "Workflow not found" on
refine → wrong `workflow_id`.

---

## plungeai_executions

**Purpose:** browse and manage the caller's execution history. Outputs are
final user-ready markdown — relay tables and threads verbatim.

**Actions**

| Action | Requires | Returns |
|---|---|---|
| `list` | — (optional `workflow_id` filter, `limit` default 20, `offset`) | Table: ID · Question (the run's own input) · Workflow · Status · When (newest first). |
| `get` | `execution_id` | Same view as `plungeai_get_workflow_status`. |
| `output` | `execution_id` | Same as `plungeai_get_result`. |
| `conversation` | `execution_id` | The run's follow-up thread (all User/Agent turns). |
| `delete` | `execution_id` | Removes the run row and its stored result (the run's follow-up conversation thread is not purged). |

**Example:** `{"user_request": "show my last 10 runs", "action": "list", "limit": 10}`

**Failures & fixes:** "Execution not found." → foreign/wrong id. "No
conversation thread for this execution yet." → the run had no follow-ups —
offer `plungeai_followup`. "Conversation storage is temporarily unavailable"
→ transient, retry.

**Numbered references:** when the user says "show me #2", resolve against the
exact list YOU displayed earlier in the conversation and use that row's ID —
never against a fresh `list`, because new runs shift the numbering.

---

## plungeai_templates — instantiating a template as a workflow (`action: "use"`)

**Purpose:** the workflow-template gallery — browse, inspect, and turn a
template into your own saved workflow. Browsing (`action: "list"`/`"get"`) is
documented in the **plungeai-discovery** skill
(`references/list-and-contract.md`); this section covers `action: "use"`,
which is workflow authoring, not discovery — it creates a saved workflow you
then run and iterate like any other.

**Parameters**

| Param | Type | Notes |
|---|---|---|
| `action` | `"list"` \| `"get"` \| `"use"` | `list`/`get` — see `plungeai-discovery`. |
| `template_id` | string, required | The template to instantiate (from a `list`/`get` call). |
| `name` | string ≤512 | The new workflow's name. Default `<template name> (copy)` — except a **bot**-kind template, which defaults to the template's own name with no "(copy)" suffix. |
| `folder` | string | Files the new workflow into a folder by name. A miss is non-fatal — the workflow is still created, with a ⚠️ "created without a folder" note. |

**Example**

```json
{"user_request": "start from a research template", "action": "use",
 "template_id": "tpl-...", "name": "My research pipeline", "folder": "Research"}
```

**Returns:** creates a saved workflow that carries the template's `kind`
(`workflow`/`agent`/`bot`) and its full YAML content, bumps the template's
usage count, and replies "Created workflow **<name>** (`<id>`) from template
**<template>**. ... Run it with plungeai_execute_workflow." Iterate the
result afterward with `plungeai_workflow {action: "update"}` like any other
saved workflow — `use` does not create a special kind of object.

**Failures & fixes:** `use` without `template_id` → "template_id is required
for this action." — supply the id from a `list` call. Unknown `template_id`
→ "Template not found: <id>" — re-list, ids can go stale. "Template content
missing from storage." → a platform-side gap; report it rather than
retrying.
