# PlungeAI API Overview Source: https://docs-preview.plungeai.com/getting-started/overview ## Set up PlungeAI via MCP One server, 20 tools. Needs an ozk_ key from Dashboard → One API → Keys. Works in every major coding agent. [See all install options →](/developer-tools/mcp/quickstart) **Run in terminal.** Run this command in your terminal. Set PLUNGE_API_KEY first; the header is stored in your Claude Code config. ```bash claude mcp add --transport http plungeai https://mcp.plungeai.com/v1 --header "Authorization: Bearer $PLUNGE_API_KEY" ``` **Verify installation:** Run /mcp to see plungeai, then ask: use plungeai_whoami to confirm my identity [Learn more](/integrations/claude-code) **Run in terminal.** Run this command in your terminal. Codex reads the key from PLUNGEAI_API_KEY at run time: export PLUNGEAI_API_KEY=$PLUNGE_API_KEY. ```bash codex mcp add plungeai --url https://mcp.plungeai.com/v1 --bearer-token-env-var PLUNGEAI_API_KEY ``` **Verify installation:** /mcp lists plungeai [Learn more](/integrations/codex) **One-click install.** Add PlungeAI to Cursor: [Add to Cursor →](https://mcp.plungeai.com/install/cursor) Then add the Authorization header in ~/.cursor/mcp.json (user-level file, never a repo file). **Verify installation:** In agent chat: use plungeai_whoami to confirm my identity [Learn more](/integrations/cursor) **One-click install.** Add PlungeAI to VS Code: [Add to VS Code →](https://mcp.plungeai.com/install/vscode) Or from a terminal: ```bash code --add-mcp "{\"name\":\"plungeai\",\"type\":\"http\",\"url\":\"https://mcp.plungeai.com/v1\",\"headers\":{\"Authorization\":\"Bearer $PLUNGE_API_KEY\"}}" ``` **Verify installation:** In Copilot agent chat: plungeai_whoami [Learn more](/integrations/vscode) These docs use PLUNGE_API_KEY; the PlungeAI skills, the Claude Code plugin and the install page use PLUNGEAI_API_KEY; any name works if your config and shell agree. ## Onboard your agent Connect PlungeAI by pasting this prompt to your agent. ```text Use curl to read https://docs.plungeai.com/agents.md and perform the setup to connect PlungeAI ``` The file it reads, [/agents.md](/agents.md), asks you for a key, connects your client to the MCP server, verifies the connection with `plungeai_whoami` and lists the rules the agent follows. ## Build with PlungeAI APIs Pick a product and open its quickstart. Not sure which API to use? Try the [API chooser](/getting-started/choose-an-api). [Create an API key](https://dashboard.plungeai.com/one-api?tab=keys) OpenAI-compatible chat with fallback and presets. Key: `sk-ocean-`. A typed tool call behind a trust fence. Key: `ozk_`. One prompt, sync, async or streamed. Key: `ozk_`. Multi-agent CNL pipelines, inline or saved. Key: `ozk_`. An agent loop inside allowed tools and iterations. Key: `ozk_`. Cron agents, heartbeats and notifications. Key: `ozk_`. Find agents, tools and models before you call. Key: `ozk_`. # Choose an API Source: https://docs-preview.plungeai.com/getting-started/choose-an-api ## What are you building? Find your job in the first column, answer its question, and start with the API the answer names. | Job | Question | Answer → start with | |---|---|---| | **Call a model from my code**: chat or embeddings in my app | Do you need one fixed model, or automatic fallback? | One model → [Chat completions](#start-with-chat-completions) · Fallback, cheapest or fastest → [Model routing](#start-with-model-routing) | | **Run one capability**: search, scrape, send, look up | Do you already know which tool? | Yes → [Tools](#start-with-tools) · No → [Discovery](#start-with-discovery) | | **Get an answer from an agent**: one prompt in, an answer out | Do you need the answer now, or can it arrive later? | Now (or streamed) → [Agents (sync)](#start-with-agents-sync) · Later → [Agents (async)](#start-with-agents-async) | | **Chain several agents**: a pipeline with fixed steps, or an open goal | Should an agent choose the steps itself, within limits? | No, fixed steps → [Workflows](#start-with-workflows) · Yes → [Missions](#start-with-missions) | | **Run something on a schedule**: every hour, every day, on a condition | none | [Scheduling](#start-with-scheduling) | | **Work from my coding agent**: Claude Code, Cursor, Codex, VS Code | none | [the MCP server](#start-with-the-mcp-server) | The interactive chooser is planned (TI-74); until then this table and the results below carry the same data. ### Start with Chat completions You call one model you already chose through the OpenAI-compatible chat API, so any OpenAI SDK works once you change the base URL. **How to start:** base URL `https://api.plungeai.com/v1`; key `$PLUNGE_MODEL_KEY` (an `sk-ocean-` key); `model` set to a slug from `GET /v1/models`; `stream: true` if you want SSE chunks. [Setup details →](/models/quickstart) · [Build with Chat completions →](/models/quickstart) | | | |---|---| | What you send | `POST /v1/chat/completions` with `model`, `messages` and an `sk-ocean-` key | | What you get back | `chat.completion` (or SSE chunks) with `usage` | | What your app handles | Retries on 429 `rate_limit_exceeded` and 5xx; model choice | | How long it takes | One model call; streaming starts at the first token | | What you pay for | Tokens, billed at provider cost × your org markup ([Pricing](/getting-started/pricing)) | | What to check | `x-request-id`, `usage`, served `model` ([Models quickstart](/models/quickstart)) | **Before you build:** an `ozk_` key is rejected on the models plane with `invalid_api_key`; use an `sk-ocean-` key. ### Start with Model routing The gateway tries your candidates in order, or sorts them by price, latency or throughput, so one failing provider does not fail the request. **How to start:** the Chat completions setup plus `models: ["", ""]` and `sort` set to `price`, `latency` or `throughput`, or `model: "@preset/"` for a saved preset; the Python SDK passes these in `extra_body`. [Setup details →](/models/routing) · [Build with Model routing →](/models/routing) | | | |---|---| | What you send | The same request, plus `models[]`, `sort` or `model: "@preset/"` | | What you get back | The completion from the first candidate that succeeds; `model` names the one that served | | What your app handles | Reading which model served | | How long it takes | One call, plus failover attempts | | What you pay for | Tokens of the model that served | | What to check | The `model` field, and 502 "All routing candidates failed" | **Before you build:** read the served `model` field before you log costs; it can differ from your first candidate. ### Start with Tools You already know the capability, and one tool call gives typed params, one outcome object and the trust fence in a single request. **How to start:** key `$PLUNGE_API_KEY` (an `ozk_` key); read `GET /v1/tools/{id}` for `operations[]` and `inputSchema`; send `{operation, params}` to `POST /v1/tools/{id}/execute`. [Setup details →](/tools/quickstart) · [Build with Tools →](/tools/quickstart) | | | |---|---| | What you send | `POST /v1/tools/{id}/execute {operation, params}` with an `ozk_` key | | What you get back | `{ok, content, outcome, execution_id, request_id}` | | What your app handles | 422 `invalid_params`, 409 `approval_required`, 424 `connection_required` | | How long it takes | One tool run; `mode: async` over MCP for long ones | | What you pay for | Counts toward tier POST limits; per-call price TBD by owner (TI-31) | | What to check | `outcome`, `execution_id`, the trace ([Outcomes](/tools/outcomes)) | **Before you build:** search first; never hard-code a tool id. Handle 409 `approval_required` and 424 `connection_required` before you ship. ### Start with Discovery You do not know the right tool or agent yet, and search returns ranked cards you can read before you spend a call. **How to start:** `GET /v1/discovery/search` with `q` (your need in plain words), `kind` (for example `agents`), `mode` `hybrid` (or `keyword`, `vector`), `fields` `summary` and `limit`; page with `offset`. [Setup details →](/discovery/core-concepts/search-modes) · [Build with Discovery →](/discovery/quickstart) | | | |---|---| | What you send | `GET /v1/discovery/search?q=&kind=` | | What you get back | `{cards, count, searchMethod, query}` | | What your app handles | Picking an id, then reading the contract | | How long it takes | One synchronous GET | | What you pay for | GETs are not rate-limited; price TBD by owner | | What to check | `status:active` on the card ([Card status](/discovery/core-concepts/card-status)) | **Before you build:** call only cards with `status: active`; search filters on `active` by default, so widen `status` only on purpose. ### Start with Agents (sync) One prompt in and one answer out on the same connection is the shortest path to a registry agent, and `stream: true` shows tokens as they arrive. **How to start:** key `$PLUNGE_API_KEY`; `POST /v1/agents/llm-agent/execute` with `prompt`, `sync: true` (the default) and `max_tokens`; add `stream: true` for OpenAI chunks. [Setup details →](/agents/quickstart) · [Build with Agents →](/agents/quickstart) | | | |---|---| | What you send | `POST /v1/agents/{id}/execute {prompt, sync: true}` (or `stream: true`) | | What you get back | `{content, workflow_id, task_id, request_id}` or OpenAI SSE chunks | | What your app handles | Holding the connection; keepalives | | How long it takes | One agent run on one connection | | What you pay for | The model tokens the agent uses, within the tier limit; price TBD by owner (TI-31) | | What to check | `X-Execution-Id`, `content` ([Agents quickstart](/agents/quickstart)) | **Before you build:** search first; never hard-code agent ids. `harness-agent` is not callable; loop agents run as a `type: harness` task. ### Start with Agents (async) The answer can arrive later, so the call returns at once with a 202 and you collect the result without holding a connection open. **How to start:** the Agents (sync) request with `sync: false`; store `workflow_id` and `task_id` from the 202; poll `GET /v1/agents/results/{workflowId}/{taskId}` until it stops answering 404 `not_ready`. [Setup details →](/agents/features/async-results) · [Build with Agents →](/agents/features/async-results) | | | |---|---| | What you send | The same, with `sync: false` | | What you get back | 202 `{workflow_id, task_id}`, then the results route | | What your app handles | Polling `GET /v1/agents/results/{workflowId}/{taskId}`; 404 `not_ready` means keep polling | | How long it takes | Returns immediately; the result lands later | | What you pay for | As Agents (sync) | | What to check | 409 `execution_failed`, 422 `empty_completion` ([Async results](/agents/features/async-results)) | **Before you build:** treat 409 `execution_failed` and 422 `empty_completion` as final answers, not as "not ready". ### Start with Workflows A fixed multi-step pipeline across several agents belongs in one CNL workflow, where a parallel block costs only its slowest child. **How to start:** `POST /v1/workflows/execute` with `workflow` (a CNL YAML string), `input` and `format` (`json`, `yaml`, `markdown` or `text`); `POST /v1/workflows/execute-stream` for SSE; `POST /v1/workflows/{id}/execute` for a saved workflow. [Setup details →](/workflows/quickstart) · [Build with Workflows →](/workflows/quickstart) | | | |---|---| | What you send | `POST /v1/workflows/execute {workflow, input, format}` or `execute-stream` | | What you get back | `{success, status: completed or incomplete, workflow_id, final_task_id, content}` or SSE engine events | | What your app handles | Parsing SSE events; the `incomplete` status | | How long it takes | The sum of its sequential tasks; a parallel block costs its slowest child | | What you pay for | Every model call inside the run; price TBD by owner (TI-31) | | What to check | `status`, `final_task_id`, the trace ([Results and traces](/workflows/core-concepts/results-and-traces)) | **Before you build:** search first; never hard-code agent ids. Read `status: incomplete` as a result to inspect, not as a success. ### Start with Missions An agent chooses its own steps, but only inside the tools you allow and the iteration cap you set. **How to start:** over MCP, `plungeai_run_mission` with `goal`, `allowed_tools`, `max_iterations` (1 to 50, default 8), `success_criteria` and `mode` (default `async`); over REST, a `type: harness` task in `POST /v1/workflows/execute`. [Setup details →](/missions/bounds) · [Build with Missions →](/missions/quickstart) | | | |---|---| | What you send | `plungeai_run_mission {goal, allowed_tools, max_iterations}` or a `type: harness` task | | What you get back | An execution id (async by default), then the result | | What your app handles | Polling status; relaying "AWAITING USER APPROVAL" and calling `plungeai_continue`; a trust-fence "NEEDS APPROVAL" runs only from Studio | | How long it takes | Minutes; resumable legs of about ten minutes | | What you pay for | The model calls in each iteration; price TBD by owner (TI-31) | | What to check | `continuation` in the status output ([Bounds](/missions/bounds)) | **Before you build:** the mission tool has no REST endpoint yet (TI-24). Relay "AWAITING USER APPROVAL" to the user before `plungeai_continue`. ### Start with Scheduling Recurring agents, queries, workflows and heartbeats run on a cron schedule with notifications, with no server of your own. **How to start:** `plungeai_schedule` with `action: create`, `name`, `job_type` (`agent`, `query`, `workflow` or `heartbeat`), `target`, `schedule` (cron), `timezone` and `notify_channel`; then `action: get` and `action: runs`. [Setup details →](/scheduling/quickstart) · [Build with Scheduling →](/scheduling/quickstart) | | | |---|---| | What you send | `plungeai_schedule {action: create, job_type, target, schedule}` | | What you get back | `job_id`; runs on the cron schedule | | What your app handles | Verifying with `get` and `runs`; notification channel ids | | How long it takes | Runs on the schedule | | What you pay for | Each run, priced like the job type it runs (TI-31) | | What to check | Run history ([Runs](/scheduling/runs)) | **Before you build:** MCP only today (TI-24). Verify every job you create with `get` and `runs`. ### Start with the MCP server Your coding agent gets all 20 `plungeai_*` tools from one server, so you write no client code. **How to start:** URL `https://mcp.plungeai.com/v1`; header `Authorization: Bearer $PLUNGE_API_KEY` (an `ozk_` key); transport Streamable HTTP; one command or deeplink per client. [Setup details →](/developer-tools/mcp/quickstart#client-installation) · [Build with the MCP server →](/developer-tools/mcp/plungeai-mcp) | | | |---|---| | What you send | One install command or deeplink ([Overview](/getting-started/overview)) | | What you get back | 20 `plungeai_*` tools, 5 resources, 1 prompt in your client | | What your app handles | Nothing: the client calls the tools | | How long it takes | One install step, then the client is ready | | What you pay for | Whatever the tools run | | What to check | `plungeai_whoami` ([MCP quickstart](/developer-tools/mcp/quickstart)) | **Before you build:** keep the key in your user-level client config or shell, never in a repo file; call `plungeai_whoami` to confirm the connection. ## Have your agent choose an API The `choose-your-plungeai-door` skill teaches your agent the same choice. Download [choose-your-plungeai-door.zip](https://skills.plungeai.com/choose-your-plungeai-door.zip) and add it as a skill. Download [choose-your-plungeai-door.zip](https://skills.plungeai.com/choose-your-plungeai-door.zip) and add it with your Codex skill installer. The skill as a docs page. Source repository: TBD by owner (TI-12). ## Go straight to a quickstart - [Call any model](/models/quickstart) - [Run a tool](/tools/quickstart) - [Run an agent](/agents/quickstart) - [Run a workflow](/workflows/quickstart) - [Run a bounded mission](/missions/quickstart) - [Schedule a job](/scheduling/quickstart) - [Discover capabilities](/discovery/quickstart) Nothing you choose here is saved. # PlungeAI API Pricing Source: https://docs-preview.plungeai.com/getting-started/pricing Planned: not available yet. Tracked as TI-74. ## What this will do How PlungeAI meters and bills model calls and runs. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # API Rate Limits Source: https://docs-preview.plungeai.com/getting-started/rate-limits Every key has a tier, copied onto the key when it is created. The tier sets per-minute and per-day windows on the execution planes and the MCP server; the models plane has one per-key limit for every tier. | Surface | Counted on | free | pro | enterprise | |---|---|---|---|---| | Execution planes on `https://api.plungeai.com` (tools, agents, workflows, discovery, traces) | `POST` requests only; catalog `GET`s are not counted; a per-key override is ignored | 30/min · 1,000/day | 100/min · 10,000/day | 300/min · 100,000/day | | MCP server `https://mcp.plungeai.com/v1` | `tools/call` only; a per-key `rate_limit` override set by PlungeAI is honoured | 30/min · 1,000/day | 100/min · 10,000/day | 300/min · 100,000/day | | Models plane (`/v1/chat/completions`, `/v1/embeddings`, `/v1/models`) | Every request, per key | 600 req/min | 600 req/min | 600 req/min | | Failed authentication | Per client IP, any tier | 20/min · 500/day | n/a | n/a | A key with no tier counts as free. When you hit a limit you get 429 with Retry-After (seconds): `rate_limited` on the execution planes, `rate_limit_exceeded` on the models plane, and JSON-RPC -32000 with `error.data.retryAfter` on MCP. There are no X-RateLimit-* headers; call `plungeai_whoami` to see your live window. ## Pricing Rate limits are separate from billing: `insufficient_quota`, `spend_cap_exceeded` and `insufficient_balance` come from billing caps, not from these windows. See [Pricing](/getting-started/pricing). ## Need higher limits? Contact PlungeAI support and quote your `x-request-id`. Support contact: TBD by owner (TI-62). # Your first calls Source: https://docs-preview.plungeai.com/getting-started/quickstart Four steps from no account to a working agent call, model call and MCP connection. Every command reads its key from an environment variable; no example contains a key. ## 1. Get a key Sign in at https://dashboard.plungeai.com and open **Dashboard → One API → Keys**. Name the key and pick an expiry: never, or 7, 30, 90, 180 or 365 days. The key starts with `ozk_` and is shown exactly once. Create an `sk-ocean-` key on the same page for step 3. ```bash export PLUNGE_API_KEY=ozk_... # execution planes and MCP export PLUNGE_MODEL_KEY=sk-ocean-... # models plane ``` Which key opens which route is on [Authentication & keys](/getting-started/authentication#the-three-prefixes). ## 2. Call an agent One prompt to the registry agent `llm-agent`, answered on the same connection: ```python Python import os, requests r = requests.post( "https://api.plungeai.com/v1/agents/llm-agent/execute", headers={"Authorization": f"Bearer {os.environ['PLUNGE_API_KEY']}"}, json={"prompt": "In one sentence: what is a content delivery network?", "sync": True, "max_tokens": 60}, ) print(r.json()["content"]) ``` ```typescript TypeScript const r = await fetch('https://api.plungeai.com/v1/agents/llm-agent/execute', { method: 'POST', headers: { Authorization: `Bearer ${process.env.PLUNGE_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: 'In one sentence: what is a content delivery network?', sync: true, max_tokens: 60 }), }) console.log((await r.json()).content) ``` ```java Java var client = java.net.http.HttpClient.newHttpClient(); var request = java.net.http.HttpRequest.newBuilder(java.net.URI.create("https://api.plungeai.com/v1/agents/llm-agent/execute")) .header("Authorization", "Bearer " + System.getenv("PLUNGE_API_KEY")) .header("Content-Type", "application/json") .POST(java.net.http.HttpRequest.BodyPublishers.ofString("{\"prompt\":\"In one sentence: what is a content delivery network?\",\"sync\":true,\"max_tokens\":60}")) .build(); System.out.println(client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString()).body()); ``` ```bash cURL curl -s -X POST https://api.plungeai.com/v1/agents/llm-agent/execute \ -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' \ -d '{"prompt":"In one sentence: what is a content delivery network?","sync":true,"max_tokens":60}' ``` The answer is in `content`. Add `"stream": true` to get OpenAI-shaped chunks that end with `data: [DONE]`. ## 3. Call a model The models plane is OpenAI-compatible: point the OpenAI SDK at `https://api.plungeai.com/v1` and pass a `provider/model` slug from `GET /v1/models`. ```python Python import os from openai import OpenAI client = OpenAI(api_key=os.environ["PLUNGE_MODEL_KEY"], base_url="https://api.plungeai.com/v1") resp = client.chat.completions.create( model="anthropic/claude-sonnet-4-6", messages=[{"role": "user", "content": "Reply with exactly the word: pong"}], max_tokens=16, ) print(resp.choices[0].message.content) ``` ```typescript TypeScript import OpenAI from 'openai' const client = new OpenAI({ apiKey: process.env.PLUNGE_MODEL_KEY, baseURL: 'https://api.plungeai.com/v1' }) const resp = await client.chat.completions.create({ model: 'anthropic/claude-sonnet-4-6', messages: [{ role: 'user', content: 'Reply with exactly the word: pong' }], max_tokens: 16, }) console.log(resp.choices[0].message.content) ``` ```java Java var client = java.net.http.HttpClient.newHttpClient(); var request = java.net.http.HttpRequest.newBuilder(java.net.URI.create("https://api.plungeai.com/v1/chat/completions")) .header("Authorization", "Bearer " + System.getenv("PLUNGE_MODEL_KEY")) .header("Content-Type", "application/json") .POST(java.net.http.HttpRequest.BodyPublishers.ofString("{\"model\":\"anthropic/claude-sonnet-4-6\",\"messages\":[{\"role\":\"user\",\"content\":\"Reply with exactly the word: pong\"}],\"max_tokens\":16}")) .build(); System.out.println(client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString()).body()); ``` ```bash cURL curl -s https://api.plungeai.com/v1/chat/completions \ -H "Authorization: Bearer $PLUNGE_MODEL_KEY" -H 'Content-Type: application/json' \ -d '{"model":"anthropic/claude-sonnet-4-6","messages":[{"role":"user","content":"Reply with exactly the word: pong"}],"max_tokens":16}' ``` The `model` field of the response names the model that served the request; after a failover it can differ from the one you asked for. These models-plane examples are verified against code, not live. ## 4. Connect your coding agent One command connects Claude Code to the MCP server and its 20 `plungeai_*` tools: ```bash claude mcp add --transport http plungeai https://mcp.plungeai.com/v1 \ --header "Authorization: Bearer $PLUNGE_API_KEY" --scope user ``` `--scope user` keeps the entry in `~/.claude.json`, outside your repository; never use `--scope project` with a literal key. Run `/mcp` in a session to see `plungeai`, then ask: use plungeai_whoami to confirm my identity. Every other client is on the [MCP quickstart](/developer-tools/mcp/quickstart#client-installation). ## Request ids and traces Every response carries a server-minted `x-request-id`; quote it when you report a problem. To group several calls into one trace, send your own UUID in `x-trace-id` and read the trace with `GET /v1/traces/{id}`: ```bash curl -s "https://api.plungeai.com/v1/traces/$(uuidgen)" -H "Authorization: Bearer $PLUNGE_API_KEY" ``` A trace id you already used on an execution returns `409 duplicate_execution_id`: send a fresh UUID each time. ## Next steps The seven planes and how a request flows. Match your job to a plane. Every field of the agent call. # Authentication & keys Source: https://docs-preview.plungeai.com/getting-started/authentication Every route except `GET /health` and `GET /v1/openapi.json` needs a key. Each of the three prefixes opens a different set of routes, and sending the wrong prefix is a `401`, never a silent fallback. These docs use PLUNGE_API_KEY; the PlungeAI skills, the Claude Code plugin and the install page use PLUNGEAI_API_KEY; any name works if your config and shell agree. ## The three prefixes | Prefix | Opens | Variable in these docs | |---|---|---| | `ozk_` | The six execution planes (tools, agents, workflows, MCP, discovery, traces) and the MCP server `https://mcp.plungeai.com/v1` | `$PLUNGE_API_KEY` | | `sk-ocean-` | The models plane only: `/v1/chat/completions`, `/v1/embeddings`, `/v1/models` | `$PLUNGE_MODEL_KEY` | | `sk-conn-` | The connector proxy on `gateway.plungeai.com` | `$PLUNGE_CONNECTOR_KEY` | ## Which routes accept which key The execution planes (`/v1/discovery`, `/v1/tools`, `/v1/agents`, `/v1/workflows`, `/v1/mcp`, `/v1/traces`) accept only a bearer that starts with `ozk_`. The models plane accepts only `sk-ocean-`. Both mistakes answer `401`: ```bash # ozk_ key on the models plane → 401 curl -s -o /dev/null -w '%{http_code}\n' -X POST https://api.plungeai.com/v1/chat/completions \ -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' \ -d '{"model":"anthropic/claude-haiku-4-5","messages":[{"role":"user","content":"hi"}],"max_tokens":1}' ``` The `401` body is the standard error envelope, and `X-Error-Code: unauthorized` carries the same code as a header. ## Header forms | Header | Accepted on | |---|---| | `Authorization: Bearer ` | Every plane and the MCP server | | `X-API-Key: ` | The execution planes and the MCP server (`ozk_` keys) | ```bash Authorization curl -s "https://api.plungeai.com/v1/tools?limit=1" -H "Authorization: Bearer $PLUNGE_API_KEY" ``` ```bash X-API-Key curl -s "https://api.plungeai.com/v1/tools?limit=1" -H "X-API-Key: $PLUNGE_API_KEY" ``` ## How to obtain each key All three are self-service at **Dashboard → One API → Keys** (https://dashboard.plungeai.com/one-api?tab=keys). Name the key, pick an expiry (never, or 7, 30, 90, 180 or 365 days) and copy it: it is shown exactly once and stored hashed. A new key takes your account's tier. ## Expiry, revocation and rotation - **Expiry** is checked on every request; an expired key answers `401` from that moment. - **Revoke** a key from the same Keys list. Keys are cached briefly, so a revoked key can keep working for about two minutes before it answers `401`. If a key leaked, revoke it first and allow for that window. - **Rotate** without downtime: create the new key, update every client, confirm it with `plungeai_whoami`, then revoke the old key. - A lost key cannot be recovered, because only its hash is stored: create a replacement and revoke the old one. ## Key fences Key fences are set by PlungeAI on request. Keys you create in the Dashboard carry no fence: every tool, from any address. On `https://mcp.plungeai.com/v1`, a key fenced to some tools does not see the others in `tools/list`, and a call to one answers JSON-RPC `-32602`; a key fenced to some addresses answers `401` from anywhere else. ## Checking yourself: plungeai_whoami Ask your MCP client to "use plungeai_whoami", or call it directly. It returns the user, the auth type and tier, the key label and the current rate-limit window: ```bash 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_whoami","arguments":{"user_request":"who am I?"}}}' ``` The fields are on [Who am I](/account-api/identity/whoami). ## CORS The One API answers browser requests from any origin, and the models plane exposes `x-request-id`. Browser code works, but a key in client-side code is a key anyone can read: call PlungeAI from your server. ## Keeping the key safe Treat the key like a password: whoever holds it acts as your account. If a key may have leaked, rotate it now. - Keep the literal key in a user-level client config or an environment variable. A config file inside a repository only references a variable. - Before the first commit in a repository you configured, both commands must print nothing: ```bash git grep -n "ozk_" grep -rn "ozk_" . --exclude-dir=.git --exclude-dir=node_modules ``` - Never put a key in browser code or a client bundle. # How PlungeAI works Source: https://docs-preview.plungeai.com/getting-started/concepts The One API is one HTTPS front door, `https://api.plungeai.com`, with one router behind it. The MCP server, `https://mcp.plungeai.com/v1`, gives coding agents the same capabilities as tools. ## The seven planes | Plane | What it does | Key routes | Key | |---|---|---|---| | Models | OpenAI-compatible chat, embeddings and model catalog, with ordered fallback, `sort`, `@preset/`, guardrails and an opt-in response cache | `POST /v1/chat/completions` · `POST /v1/embeddings` · `GET /v1/models` | `sk-ocean-` | | Tools | List tool agents, read a tool's invocation contract, execute one operation behind a trust fence | `GET /v1/tools` · `GET /v1/tools/{id}` · `POST /v1/tools/{id}/execute` | `ozk_` | | Agents | Execute a registry agent from a prompt: sync, async pointer, or OpenAI-shaped SSE | `GET /v1/agents` · `POST /v1/agents/{id}/execute` · `GET /v1/agents/results/{workflowId}/{taskId}` | `ozk_` | | Workflows | Run a multi-agent CNL workflow, inline or saved, with optional SSE | `POST /v1/workflows/execute` · `POST /v1/workflows/execute-stream` · `POST /v1/workflows/{id}/execute` | `ozk_` | | MCP | Outbound MCP runs against catalog servers; coding agents connect to the MCP server | `GET /v1/mcp/tools` · `POST /v1/mcp/runs` | `ozk_` | | Discovery | Search and recommend across the capability registry | `GET /v1/discovery/search` · `POST /v1/discovery/recommend` · `GET /v1/discovery/cards/{type}/{id}` | `ozk_` | | Traces | Read the persisted execution trace for one trace id | `GET /v1/traces/{id}` | `ozk_` | The machine-readable route list is `GET /v1/openapi.json`; this site serves the same operations at [/openapi.json](/openapi.json). ## Positioning Think of the One API as an OpenRouter-compatible models plane plus everything a model router cannot do. The models plane speaks the OpenAI wire format, so an OpenAI or OpenRouter integration moves over with a base-URL swap. The execution planes are the part a router has no answer for: real tools with contracts and a trust fence, registry agents, multi-agent workflows, discovery, MCP, and a persisted trace for every run. ## The MCP endpoint The MCP server is `https://mcp.plungeai.com/v1`: Streamable HTTP, JSON-RPC over `POST`, 20 `plungeai_*` tools, one prompt and five resources plus three resource templates. The pre-2026-09-20 path `/mcp` on the same host still answers with the same handler as a legacy alias; configure `/v1`. Details: [MCP Reference](/mcp-reference/overview). ## How a request flows An execution-plane call runs router → CNL engine → agent: ```mermaid flowchart LR client[Your code] -->|ozk_ key| router[One API router] router -->|service binding| engine[CNL engine] engine --> agent[Registry agent] agent --> memory[(Result and trace)] ``` 1. The router checks the `ozk_` key, mints the `x-request-id`, and adopts your UUID `x-trace-id` or generates a trace id. 2. The CNL engine loads the agent card from the registry and refuses any agent that is not `status:active` before it runs. 3. The agent's result is stored and returned, and the whole run is persisted as trace spans. Every call gets the same outcome vocabulary (`ok`, `needs_input`, `needs_connection`, `needs_api_key`, `needs_approval`, `unavailable`, `error`) and the same trust fence, whether it comes from a workflow, Ocean Studio or your code. ## Tool families | Family | MCP tools | |---|---| | Discover | `plungeai_list_agents`, `plungeai_get_tool_contract`, `plungeai_templates` (list, get) | | Run a tool | `plungeai_execute_tool` | | Run an agent | `plungeai_execute_agent`, `plungeai_run_mission` | | Workflows | `plungeai_list_workflows`, `plungeai_execute_workflow`, `plungeai_workflow`, `plungeai_build_workflow`, `plungeai_templates` (use) | | Runs and results | `plungeai_get_result`, `plungeai_get_workflow_status`, `plungeai_executions`, `plungeai_followup`, `plungeai_continue` | | Chat, memory, skills | `plungeai_chat`, `plungeai_memory`, `plungeai_learn` | | Scheduling | `plungeai_schedule` | | Identity | `plungeai_whoami` | A registry agent is a platform building block in the catalog; "your workflows" are the CNL workflows you saved. ## Live-verified examples Execution-plane examples on this site come from the One API and MCP guides, whose read-only examples were run against the deployed API and are re-run by the guides' example verifier. Models-plane (`sk-ocean-`) examples are verified against code, not live. Examples that run a model or spend credits say so in the text. ## Where to get help Service health. Error codes and what to do. llms.txt, markdown pages and /agents.md. Every response carries an `x-request-id`: include it when you report a problem. Support contact: TBD by owner (TI-62). # Models Plane Quickstart Source: https://docs-preview.plungeai.com/models/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do OpenAI-compatible chat completions with one `sk-ocean-` key and a base-URL swap. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Models Best Practices Source: https://docs-preview.plungeai.com/models/best-practices Planned: not available yet. Tracked as TI-74. ## What this will do Request fields, tools and structured output, and what each provider supports. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Evaluating Models Source: https://docs-preview.plungeai.com/models/evaluating-models Planned: not available yet. Tracked as TI-77. ## What this will do A guide to comparing models and agents on your own gold set: run the same prompts through several models, score the answers, and read cost and latency next to quality. No evaluation guide exists yet. ## Use this today Send one request across an ordered list of models, sorted by price, latency or throughput. Every model with its provider cost basis. # Routing: models, sort, failover Source: https://docs-preview.plungeai.com/models/routing Planned: not available yet. Tracked as TI-74. ## What this will do Ordered fallback with `models[]`, `sort` by price, latency or throughput, and presets. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Migrate to PlungeAI Source: https://docs-preview.plungeai.com/models/migrate Planned: not available yet. Tracked as TI-74. ## What this will do Move from OpenRouter, the OpenAI SDK, LiteLLM or the Vercel AI SDK. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Advanced Models Settings Source: https://docs-preview.plungeai.com/models/advanced-settings Planned: not available yet. Tracked as TI-74. ## What this will do Guardrails, the opt-in response cache and BYOK-or-billed routing. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Upgrade from guide 2.0 to 3.0 Source: https://docs-preview.plungeai.com/models/migration-guide Planned: not available yet. Tracked as TI-74. ## What this will do What changed between the 2.0 and 3.0 developer guides, for every plane. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Embeddings Quickstart Source: https://docs-preview.plungeai.com/models/embeddings Planned: not available yet. Tracked as TI-74. ## What this will do OpenAI-compatible embeddings (`openai/*` models only). This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Models, providers and slugs Source: https://docs-preview.plungeai.com/models/catalog Planned: not available yet. Tracked as TI-74. ## What this will do Read the live catalog with `GET /v1/models` and pick a model id. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Models Billing & Metering Source: https://docs-preview.plungeai.com/models/billing Planned: not available yet. Tracked as TI-74. ## What this will do Account status, price = cost × org markup, reserve-then-settle, spend caps. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Migrate from the legacy SDKs Source: https://docs-preview.plungeai.com/models/sdk-migration Planned: not available yet. Tracked as TI-74. ## What this will do Move from `@ocean-platform/external-sdk` and the Python, Go and Rust SDKs. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Models Streaming Source: https://docs-preview.plungeai.com/models/streaming Planned: not available yet. Tracked as TI-74. ## What this will do SSE chat completions, translated for non-OpenAI providers. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Workflows Quickstart Source: https://docs-preview.plungeai.com/workflows/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do Run multi-agent CNL workflows inline or saved, sync or streamed. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Workflow Best Practices Source: https://docs-preview.plungeai.com/workflows/best-practices Planned: not available yet. Tracked as TI-74. ## What this will do Write CNL that validates, runs, and fails loudly. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # The CNL workflow spec Source: https://docs-preview.plungeai.com/workflows/core-concepts/cnl Planned: not available yet. Tracked as TI-74. ## What this will do Workflow structure, task types and validation rules. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Choosing agents and models Source: https://docs-preview.plungeai.com/workflows/core-concepts/agents-and-models Planned: not available yet. Tracked as TI-74. ## What this will do Agent tiers, model pinning, and how much time parallel fan-out takes. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Workflow Runs Lifecycle Source: https://docs-preview.plungeai.com/workflows/core-concepts/run-lifecycle Planned: not available yet. Tracked as TI-74. ## What this will do Create a run, read its status and result, cancel it. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Results and traces Source: https://docs-preview.plungeai.com/workflows/core-concepts/results-and-traces Planned: not available yet. Tracked as TI-74. ## What this will do What a run returns and how to read its persisted trace. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Follow-ups and continuation Source: https://docs-preview.plungeai.com/workflows/core-concepts/follow-ups Planned: not available yet. Tracked as TI-74. ## What this will do Chain a run with follow-ups and answer paused runs. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Interactive Chat Source: https://docs-preview.plungeai.com/workflows/examples/chat Planned: not available yet. Tracked as TI-74. ## What this will do A multi-turn chat session over MCP. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Deep Research Source: https://docs-preview.plungeai.com/workflows/examples/deep-research Planned: not available yet. Tracked as TI-74. ## What this will do A goal-driven research workflow that answers with sources. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Batch Enrichment Source: https://docs-preview.plungeai.com/workflows/examples/enrichment Planned: not available yet. Tracked as TI-74. ## What this will do Enrich a list of items with a `type: batch` workflow, then run it to completion. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # Workflow Webhooks Source: https://docs-preview.plungeai.com/workflows/webhooks Planned: not available yet. Tracked as TI-25. ## What this will do PlungeAI will call a URL you register when a workflow run finishes, so you do not have to hold a stream open or poll. Nothing sends outbound webhooks today. ## Use this today Follow a run live over SSE. Start a run without waiting and fetch the result later. # Parallel and batch tasks Source: https://docs-preview.plungeai.com/workflows/parallel-tasks Planned: not available yet. Tracked as TI-74. ## What this will do Fan out with `type: parallel` and run a per-item pipeline with `type: batch`. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill reference that covers the same ground. # Generate a workflow from a goal Source: https://docs-preview.plungeai.com/workflows/generate Planned: not available yet. Tracked as TI-74. ## What this will do `plungeai_build_workflow` turns a goal into CNL YAML. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Workflow streaming events Source: https://docs-preview.plungeai.com/workflows/streaming-events Planned: not available yet. Tracked as TI-74. ## What this will do SSE engine frames from `execute-stream`. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # MCP servers inside workflows Source: https://docs-preview.plungeai.com/workflows/mcp-tool-calling Planned: not available yet. Tracked as TI-74. ## What this will do Give a harness task MCP servers to call. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Saved workflows and versions Source: https://docs-preview.plungeai.com/workflows/saved-workflows Planned: not available yet. Tracked as TI-74. ## What this will do Save, version and run workflows by id. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Agents Quickstart Source: https://docs-preview.plungeai.com/agents/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do Execute a registry agent from a prompt: sync, async or streamed. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Conversations and personas Source: https://docs-preview.plungeai.com/agents/features/conversations Planned: not available yet. Tracked as TI-74. ## What this will do Carry context with `messages[]` (partial: `prompt` stays required and threading depends on the agent), `persona`, and MCP `session_id` for reliable threading. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Output formats Source: https://docs-preview.plungeai.com/agents/features/output-formats Planned: not available yet. Tracked as TI-74. ## What this will do JSON, YAML, Markdown or text via `format` and `Accept`. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Agent streaming Source: https://docs-preview.plungeai.com/agents/features/streaming Planned: not available yet. Tracked as TI-74. ## What this will do OpenAI-shaped chunks with keepalives and `X-Execution-Id`. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Citations Source: https://docs-preview.plungeai.com/agents/features/citations Planned: not available yet. Tracked as TI-76. ## What this will do Agent answers will carry source annotations that tie each claim to the page or document it came from. Agent results have no citation field today. ## Use this today A multi-step research workflow you can run today. # Web search tool agents Source: https://docs-preview.plungeai.com/agents/features/web-search Planned: not available yet. Tracked as TI-74. ## What this will do Search the web through registry tool agents. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Outbound MCP runs Source: https://docs-preview.plungeai.com/agents/features/mcp-tools Planned: not available yet. Tracked as TI-74. ## What this will do Connect catalog MCP servers to a run and call their tools. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Async execution and results Source: https://docs-preview.plungeai.com/agents/features/async-results Planned: not available yet. Tracked as TI-74. ## What this will do `sync:false` returns 202; redeem the result later. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Direct requests Source: https://docs-preview.plungeai.com/agents/examples/direct-requests Planned: not available yet. Tracked as TI-74. ## What this will do Ask a question, ask for JSON, send YAML and get Markdown. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Use an agent as a subagent tool Source: https://docs-preview.plungeai.com/agents/examples/subagent Planned: not available yet. Tracked as TI-74. ## What this will do Wrap an agent call as a tool in your own orchestrator. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # OpenAI compatibility (agents plane) Source: https://docs-preview.plungeai.com/agents/openai-compatibility Planned: not available yet. Tracked as TI-74. ## What this will do Which OpenAI request and stream fields the agents plane accepts. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Discovery Quickstart Source: https://docs-preview.plungeai.com/discovery/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do Find agents, tools, models, skills and connectors before you call. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Recommend Source: https://docs-preview.plungeai.com/discovery/recommend Planned: not available yet. Tracked as TI-74. ## What this will do Ask the registry which capability fits a task. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Search modes and fields Source: https://docs-preview.plungeai.com/discovery/core-concepts/search-modes Planned: not available yet. Tracked as TI-74. ## What this will do `mode` hybrid, keyword or vector; `fields` list, summary or full. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # The card object Source: https://docs-preview.plungeai.com/discovery/core-concepts/cards Planned: not available yet. Tracked as TI-74. ## What this will do What a registry card holds and how to read one. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Card status and kinds Source: https://docs-preview.plungeai.com/discovery/core-concepts/card-status Planned: not available yet. Tracked as TI-74. ## What this will do Only `status:active` cards run; kinds you can filter on. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Inspect a tool contract Source: https://docs-preview.plungeai.com/discovery/features/tool-contract Planned: not available yet. Tracked as TI-74. ## What this will do Read operations, required params and examples before executing. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Quality signals Source: https://docs-preview.plungeai.com/discovery/features/quality Planned: not available yet. Tracked as TI-74. ## What this will do Add `include=quality` to search results. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Catalog resources over MCP Source: https://docs-preview.plungeai.com/discovery/features/resources Planned: not available yet. Tracked as TI-74. ## What this will do Dropped: discovery search is synchronous and has no event stream. Replacement: read catalog lists as MCP resources. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Registry kinds Source: https://docs-preview.plungeai.com/discovery/features/kinds Planned: not available yet. Tracked as TI-74. ## What this will do Dropped: there is no long-running discovery run to notify on. Replacement: the kinds you can search. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Pagination Source: https://docs-preview.plungeai.com/discovery/features/pagination Planned: not available yet. Tracked as TI-74. ## What this will do Discovery search and `GET /v1/tools` page with `limit` and `offset` and return `count`; only `GET /v1/agents` returns `has_more` and `next_offset`. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Workflow templates Source: https://docs-preview.plungeai.com/discovery/features/templates Planned: not available yet. Tracked as TI-74. ## What this will do Dropped: a search cannot be cancelled. Replacement: start from a template. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Discovery first Source: https://docs-preview.plungeai.com/discovery/features/discovery-first Planned: not available yet. Tracked as TI-74. ## What this will do Dropped: there is no stateful FindAll-style run to refresh. Replacement: the discovery-first rule. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # Scheduling Quickstart Source: https://docs-preview.plungeai.com/scheduling/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do Cron jobs for agents, queries, workflows and heartbeats. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Run now and run history Source: https://docs-preview.plungeai.com/scheduling/runs Planned: not available yet. Tracked as TI-74. ## What this will do Trigger a job now and read its run history. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Webhook triggers Source: https://docs-preview.plungeai.com/scheduling/webhook-triggers Planned: not available yet. Tracked as TI-25. ## What this will do You will be able to start a scheduled job or a workflow by calling a webhook URL on a public PlungeAI host. Inbound triggers are not available on a public host today. ## Use this today Run a workflow on a cron schedule with the plungeai_schedule MCP tool. # Heartbeat check Source: https://docs-preview.plungeai.com/scheduling/examples/heartbeat Planned: not available yet. Tracked as TI-74. ## What this will do A heartbeat job that checks a condition and acts on it. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Trigger a workflow or mission Source: https://docs-preview.plungeai.com/scheduling/examples/trigger-workflow Planned: not available yet. Tracked as TI-74. ## What this will do Run a workflow or mission on a schedule and notify a channel. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Scheduling: MCP tool → REST API Source: https://docs-preview.plungeai.com/scheduling/migration-guide Planned: not available yet. Tracked as TI-24. ## What this will do When a REST schedules API exists, this guide will map each `plungeai_schedule` action to its REST route so existing jobs keep running. Scheduling is available only through the MCP tool today. ## Use this today Create and manage schedules with plungeai_schedule on https://mcp.plungeai.com/v1. # Tools Quickstart Source: https://docs-preview.plungeai.com/tools/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do List tool agents, read a contract, execute one operation. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Outcomes and remediation Source: https://docs-preview.plungeai.com/tools/outcomes Planned: not available yet. Tracked as TI-74. ## What this will do The seven outcomes, the remediation actions, and their HTTP statuses. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Tool catalog by category Source: https://docs-preview.plungeai.com/tools/catalog Planned: not available yet. Tracked as TI-74. ## What this will do The tool agents available today, by category. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Long runs (async) Source: https://docs-preview.plungeai.com/tools/async Planned: not available yet. Tracked as TI-74. ## What this will do `mode: "async"` for tool calls that take longer than one request. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Missions Quickstart Source: https://docs-preview.plungeai.com/missions/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do Run a bounded agent loop with a goal, allowed tools and an iteration cap. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Mission bounds and the tool fence Source: https://docs-preview.plungeai.com/missions/bounds Planned: not available yet. Tracked as TI-74. ## What this will do What a mission may do and where it stops. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Skills, plugins and capability injection Source: https://docs-preview.plungeai.com/missions/capability-injection Planned: not available yet. Tracked as TI-74. ## What this will do Inject skills, experts, persona, backgrounds, plugins and MCP. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Pre-built agent cards Source: https://docs-preview.plungeai.com/missions/prebuilt-agents Planned: not available yet. Tracked as TI-74. ## What this will do Run a catalog agent card with `mission_ref` or `pack`. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Async missions: the Ten-Minute Relay Source: https://docs-preview.plungeai.com/missions/async-relay Planned: not available yet. Tracked as TI-74. ## What this will do Long missions run in resumable legs; poll for the result. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Connectors and connected accounts Source: https://docs-preview.plungeai.com/connectors/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do OAuth and API-key connectors, and how a connected account reaches a call. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # The connector proxy Source: https://docs-preview.plungeai.com/connectors/proxy Planned: not available yet. Tracked as TI-74. ## What this will do Call a provider's API raw through `gateway.plungeai.com` with an `sk-conn-` key (`$PLUNGE_CONNECTOR_KEY`). This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Traces Quickstart Source: https://docs-preview.plungeai.com/traces/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do Read the spans and gateway log of any run by trace id. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Execution history and cost Source: https://docs-preview.plungeai.com/traces/history-and-cost Planned: not available yet. Tracked as TI-74. ## What this will do List past runs and what they cost. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # The activity log Source: https://docs-preview.plungeai.com/traces/activity-log Planned: not available yet. Tracked as TI-74. ## What this will do Your key's call log on the MCP server. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Developer Tools Overview Source: https://docs-preview.plungeai.com/developer-tools/quickstart Planned: not available yet. Tracked as TI-74. ## What this will do MCP vs One API vs CLI vs Studio: pick your door. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Account API Source: https://docs-preview.plungeai.com/developer-tools/account-api Planned: not available yet. Tracked as TI-06. ## What this will do A key-authenticated Account API will let a script manage keys, the wallet and usage without the Dashboard. How that API authenticates is still open. Today every account action is a Dashboard view; the table below lists where each one lives. ## Available today in the Dashboard | What it does | Dashboard location | |---|---| | Create, list and revoke `ozk_`, `sk-ocean-` and `sk-conn-` keys | **Dashboard → One API → Keys** | | Wallet balance, top-up, auto-recharge, BYOK provider keys | **Dashboard → One API → Billing** | | Ledger of top-ups and charges | **Dashboard → Billing → Ledger** | | Usage by user, workflow, model or channel | **Dashboard → Billing → Usage** | | Request log of One API calls | **Dashboard → One API → Requests** | | Model and connector catalog (provider cost basis) | **Dashboard → One API → Catalog** | | Connected accounts | **Dashboard → Secrets & Connections → Connections** | | Teams, companies and roles | **Dashboard → Team** and **Dashboard → Workspace** | | Who am I (identity, tier, rate window) | Key-authenticated today over MCP: [plungeai_whoami](/account-api/identity/whoami) | ## Use this today Create and revoke keys in the Dashboard. Where the wallet balance lives today. # Install PlungeAI Agent Skills Source: https://docs-preview.plungeai.com/developer-tools/agent-skills Planned: not available yet. Tracked as TI-74. ## What this will do 31 skills that teach coding agents to use PlungeAI. This page is not written yet; the source below covers the same material today. ## Use this today All 31 agent skills with their install options. # Anthropic Tool Calling Source: https://docs-preview.plungeai.com/developer-tools/anthropic-tool-calling Planned: not available yet. Tracked as TI-74. ## What this will do Turn PlungeAI tool contracts into Claude tool definitions. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Claude Code Plugin Source: https://docs-preview.plungeai.com/developer-tools/claude-code-plugin Planned: not available yet. Tracked as TI-74. ## What this will do The `plungeai` plugin: 31 skills plus its own MCP server config. Install it instead of `claude mcp add`, not in addition. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Ocean CLI Source: https://docs-preview.plungeai.com/developer-tools/cli Planned: not available yet. Tracked as TI-74. ## What this will do The `ocean` command: auth, runs, workflows, schedules, registry. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # Cursor Plugin Source: https://docs-preview.plungeai.com/developer-tools/cursor-plugin Planned: not available yet. Tracked as TI-13. ## What this will do A Cursor plugin will install the PlungeAI MCP server and skills from the Cursor marketplace in one step. No Cursor plugin exists today; Cursor connects through its MCP config. ## Use this today Connect Cursor to https://mcp.plungeai.com/v1 with the one-click install. # LangChain Source: https://docs-preview.plungeai.com/developer-tools/langchain Planned: not available yet. Tracked as TI-74. ## What this will do Use the models plane from LangChain's `ChatOpenAI`. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # PlungeAI MCP Server Quickstart Source: https://docs-preview.plungeai.com/developer-tools/mcp/quickstart The PlungeAI MCP server gives any MCP client the 20 `plungeai_*` tools: discover capabilities, run tools, agents, workflows and missions, schedule jobs and read results. ## When to use PlungeAI MCP? All four surfaces use the same `ozk_` key, the same account and the same data. | Surface | What it is | Use it when | |---|---|---| | MCP server, `https://mcp.plungeai.com/v1` | The 20 `plungeai_*` tools over MCP | An AI client operates PlungeAI live: discover, run, save, schedule, remember, with approvals and continuations | | One API, `https://api.plungeai.com` | REST routes, OpenAPI at `GET /v1/openapi.json` | You write or generate code that calls PlungeAI | | Skills, `https://skills.plungeai.com` | 31 instruction packs your AI client loads | Your client should already know PlungeAI's conventions; skills complement a connection | | Ocean Studio, `https://studio.plungeai.com` | The browser app | A person builds visually, connects accounts and reviews runs | A docs MCP server that searches and reads these pages from your agent is planned, tracked as TI-35: see [Docs MCP](/developer-tools/mcp/docs-mcp). ## Endpoint | Item | Value | |---|---| | URL | `https://mcp.plungeai.com/v1` | | Transport | Streamable HTTP, JSON-RPC 2.0 over `POST` | | Authentication | `Authorization: Bearer $PLUNGE_API_KEY` or `X-API-Key: $PLUNGE_API_KEY` (an `ozk_` key); every request needs it, `tools/list` included | | Responses | JSON; `tools/call` streams as server-sent events | Create the key at **Dashboard → One API → Keys** (https://dashboard.plungeai.com/one-api?tab=keys) and export it as `PLUNGE_API_KEY` before you configure a client. ## Quick installation ### Let your agent install it Paste this prompt into your coding agent; it reads the setup file and connects itself: ```text Onboard from /agents.md Use curl to read https://docs.plungeai.com/agents.md and perform the setup to connect PlungeAI ``` Or name the server directly: ```text Add the PlungeAI MCP server Add the MCP server https://mcp.plungeai.com/v1 named plungeai to my user-level client config, with the header Authorization: Bearer and the value of my PLUNGE_API_KEY environment variable, then call plungeai_whoami to confirm the connection. ``` ### Client installation Claude Code, one command: ```bash claude mcp add --transport http plungeai https://mcp.plungeai.com/v1 \ --header "Authorization: Bearer $PLUNGE_API_KEY" --scope user ``` Codex, which reads the key from `PLUNGEAI_API_KEY`: ```bash export PLUNGEAI_API_KEY="$PLUNGE_API_KEY" codex mcp add plungeai --url https://mcp.plungeai.com/v1 --bearer-token-env-var PLUNGEAI_API_KEY ``` A project `.mcp.json` that reads the key from each developer's environment, safe to commit: ```json { "mcpServers": { "plungeai": { "type": "http", "url": "https://mcp.plungeai.com/v1", "headers": { "Authorization": "Bearer ${PLUNGE_API_KEY}" } } } } ``` One-click installs open your client's install dialog with the URL filled in; add the key afterwards in the client's user-level config: Opens Cursor's MCP install dialog. Opens VS Code's MCP install dialog. Adds the server to Replit Agent. Step-by-step pages per client: User-level `~/.cursor/mcp.json`. Copilot agent mode. Integrations → MCP Servers. Verify in any client: ask it to use plungeai_whoami to confirm your identity. These docs use PLUNGE_API_KEY; the PlungeAI skills, the Claude Code plugin and the install page use PLUNGEAI_API_KEY; any name works if your config and shell agree. # Programmatic use Source: https://docs-preview.plungeai.com/developer-tools/mcp/programmatic-use Planned: not available yet. Tracked as TI-74. ## What this will do Call the MCP server from your own code with raw JSON-RPC, and run outbound MCP servers with `/v1/mcp/runs`. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # PlungeAI MCP Source: https://docs-preview.plungeai.com/developer-tools/mcp/plungeai-mcp Planned: not available yet. Tracked as TI-74. ## What this will do The one server: install per client, configure, troubleshoot. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Workflows and missions over MCP Source: https://docs-preview.plungeai.com/developer-tools/mcp/workflows-mcp Planned: not available yet. Tracked as TI-74. ## What this will do Run workflows and missions from your coding agent, sync or async. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Protocol and transport Source: https://docs-preview.plungeai.com/developer-tools/mcp/protocol Planned: not available yet. Tracked as TI-74. ## What this will do Streamable HTTP, JSON-RPC methods, sessions, SSE progress. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Prompts and resources Source: https://docs-preview.plungeai.com/developer-tools/mcp/prompts-resources Planned: not available yet. Tracked as TI-74. ## What this will do The `/plungeai` prompt and every `plungeai://` resource. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Move MCP clients from /mcp to /v1 Source: https://docs-preview.plungeai.com/developer-tools/mcp/migrate-to-v1 Planned: not available yet. Tracked as TI-74. ## What this will do `/mcp` is a legacy alias since 2026-09-20; configure `/v1`. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Docs MCP server Source: https://docs-preview.plungeai.com/developer-tools/mcp/docs-mcp Planned: not available yet. Tracked as TI-35. ## What this will do docs.plungeai.com will run its own MCP server so an agent can search these pages and read any of them as markdown. It is a separate server from the PlungeAI MCP server, and it is not running yet. ## Use this today Read these docs as markdown today: llms.txt, llms-full.txt and a .md twin of every page. # OAuth Provider Source: https://docs-preview.plungeai.com/developer-tools/oauth-provider Planned: not available yet. Tracked as TI-05. ## What this will do MCP clients that connect only through OAuth will be able to sign in with a PlungeAI account instead of sending a key. Today the MCP server accepts bearer `ozk_` keys only. ## Use this today Connect any MCP client with an ozk_ key in the Authorization header. # Ollama Tool Calling Source: https://docs-preview.plungeai.com/developer-tools/ollama-tool-calling Planned: not available yet. Tracked as TI-74. ## What this will do Turn PlungeAI tool contracts into tool definitions for a local Ollama model through its OpenAI-compatible endpoint. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # OpenAI SDK Source: https://docs-preview.plungeai.com/developer-tools/openai-sdk Planned: not available yet. Tracked as TI-74. ## What this will do Point the OpenAI Python or TypeScript SDK at PlungeAI. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # OpenAI Tool Calling Source: https://docs-preview.plungeai.com/developer-tools/openai-tool-calling Planned: not available yet. Tracked as TI-74. ## What this will do Turn tool contracts into OpenAI function definitions and execute the calls. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Generate a client from OpenAPI Source: https://docs-preview.plungeai.com/developer-tools/openapi-codegen Planned: not available yet. Tracked as TI-74. ## What this will do Typed clients from `/v1/openapi.json`. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill reference that covers the same ground. # OpenCode Plugin Source: https://docs-preview.plungeai.com/developer-tools/opencode-plugin Planned: not available yet. Tracked as TI-74. ## What this will do Connect OpenCode today with an MCP config; a plugin is planned. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # @plungeai/one-api Source: https://docs-preview.plungeai.com/sdks/typescript Planned: not available yet. Tracked as TI-08. ## What this will do `@plungeai/one-api` will be a typed TypeScript client for the execution planes, published on npm. It is not on npm yet. Until then, generate a typed client from the OpenAPI spec. ```bash Today's path npx openapi-typescript https://api.plungeai.com/v1/openapi.json -o src/plungeai-schema.d.ts npm install openapi-fetch ``` ## Use this today Generate typed clients from https://api.plungeai.com/v1/openapi.json. # PlungeAI in Claude Code Source: https://docs-preview.plungeai.com/integrations/claude-code Planned: not available yet. Tracked as TI-74. ## What this will do One `claude mcp add` command, or a project `.mcp.json`. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in Claude.ai and Claude Desktop Source: https://docs-preview.plungeai.com/integrations/claude-ai Planned: not available yet. Tracked as TI-74. ## What this will do Skill upload on claude.ai; mcp-remote bridge on Desktop. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in Codex Source: https://docs-preview.plungeai.com/integrations/codex Planned: not available yet. Tracked as TI-74. ## What this will do `codex mcp add` with a bearer-token env var. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in Cursor Source: https://docs-preview.plungeai.com/integrations/cursor Planned: not available yet. Tracked as TI-74. ## What this will do One-click deeplink or `~/.cursor/mcp.json`. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in VS Code Source: https://docs-preview.plungeai.com/integrations/vscode Planned: not available yet. Tracked as TI-74. ## What this will do One-click install or `code --add-mcp`. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in Gemini CLI Source: https://docs-preview.plungeai.com/integrations/gemini-cli Planned: not available yet. Tracked as TI-74. ## What this will do `~/.gemini/settings.json` with `httpUrl`. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in OpenCode Source: https://docs-preview.plungeai.com/integrations/opencode Planned: not available yet. Tracked as TI-74. ## What this will do `opencode.json` remote MCP entry. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in Windsurf Source: https://docs-preview.plungeai.com/integrations/windsurf Planned: not available yet. Tracked as TI-74. ## What this will do `~/.codeium/windsurf/mcp_config.json` snippet. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in Replit Source: https://docs-preview.plungeai.com/integrations/replit Planned: not available yet. Tracked as TI-74. ## What this will do One-click install into Replit Agent. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in Lovable Source: https://docs-preview.plungeai.com/integrations/lovable Planned: not available yet. Tracked as TI-74. ## What this will do Chat connector or app connector. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in Bolt.new Source: https://docs-preview.plungeai.com/integrations/bolt Planned: not available yet. Tracked as TI-74. ## What this will do Custom MCP server in Connectors. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # PlungeAI in v0 Source: https://docs-preview.plungeai.com/integrations/v0 Planned: not available yet. Tracked as TI-74. ## What this will do Add MCP in the prompt form; the generated app cannot call MCP. This page is not written yet; the source below covers the same material today. ## Use this today The agent skill that covers the same ground. # Any other MCP client Source: https://docs-preview.plungeai.com/integrations/other-mcp-clients Planned: not available yet. Tracked as TI-74. ## What this will do URL, header and transport for clients not listed here. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Agentic payments (x402) Source: https://docs-preview.plungeai.com/integrations/agentic-payments Planned: not available yet. Tracked as TI-74. ## What this will do Pay x402 services in USDC through the payment agents, with approval. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # AWS Marketplace Source: https://docs-preview.plungeai.com/integrations/aws-marketplace Planned: not available yet. Tracked as TI-45. ## What this will do You will be able to subscribe to PlungeAI and pay through your AWS account. There is no AWS Marketplace listing today. ## Use this today Top up the wallet and see spend in Dashboard → One API → Billing. # Browser Use Source: https://docs-preview.plungeai.com/integrations/browser-use Planned: not available yet. Tracked as TI-46. ## What this will do A browser-agent integration will let a workflow read pages that need a logged-in browser. No Browser Use integration exists today. ## Use this today The tool agents you can call today. # Google Cloud Marketplace Source: https://docs-preview.plungeai.com/integrations/google-cloud-marketplace Planned: not available yet. Tracked as TI-45. ## What this will do You will be able to subscribe to PlungeAI and pay through your Google Cloud account. There is no Google Cloud Marketplace listing today. ## Use this today Top up the wallet and see spend in Dashboard → One API → Billing. # Google Gemini Enterprise Source: https://docs-preview.plungeai.com/integrations/google-gemini-enterprise Planned: not available yet. Tracked as TI-46. ## What this will do Gemini Enterprise will be able to use PlungeAI agents and tools as a grounding source. No Gemini Enterprise integration exists today. ## Use this today Use PlungeAI from Gemini CLI over MCP today. # Google Sheets Source: https://docs-preview.plungeai.com/integrations/google-sheets Planned: not available yet. Tracked as TI-46. ## What this will do A Google Sheets function will run a PlungeAI agent over a range of cells and write the answers back. No Sheets function exists today. ## Use this today Run a registry agent over the One API. # LiteLLM Source: https://docs-preview.plungeai.com/integrations/litellm Planned: not available yet. Tracked as TI-74. ## What this will do Use the models plane as an OpenAI-wire LiteLLM provider. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # n8n Source: https://docs-preview.plungeai.com/integrations/n8n Planned: not available yet. Tracked as TI-44. ## What this will do n8n nodes will run PlungeAI agents, tools and workflows inside an n8n flow. No n8n node exists today. An HTTP Request node that calls the One API is the nearest path; it is not tested end to end. ## Use this today Run a workflow over the One API. # OpenRouter compatibility Source: https://docs-preview.plungeai.com/integrations/openrouter Planned: not available yet. Tracked as TI-74. ## What this will do Endpoint and field parity with OpenRouter, and what you gain. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Render Source: https://docs-preview.plungeai.com/integrations/render Planned: not available yet. Tracked as TI-46. ## What this will do A Render template will deploy a sample app that calls PlungeAI in one click. No template exists today. ## Use this today Generate a typed client for your own app from the OpenAPI spec. # Superhuman Source: https://docs-preview.plungeai.com/integrations/superhuman Planned: not available yet. Tracked as TI-46. ## What this will do Superhuman users will be able to call PlungeAI skills from their inbox. No Superhuman integration exists today. ## Use this today Connect any MCP-capable client to https://mcp.plungeai.com/v1. # Vercel Source: https://docs-preview.plungeai.com/integrations/vercel Planned: not available yet. Tracked as TI-74. ## What this will do Vercel AI SDK against the models plane; v0 over MCP. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Zapier Source: https://docs-preview.plungeai.com/integrations/zapier Planned: not available yet. Tracked as TI-44. ## What this will do A Zapier app will run PlungeAI agents and workflows as Zap actions. No Zapier app exists today. ## Use this today Run a workflow over the One API. # Data Integrations Source: https://docs-preview.plungeai.com/data-integrations/overview Planned: not available yet. Tracked as TI-43. ## What this will do Data integrations will let Spark, DuckDB, BigQuery, Polars, Snowflake and Supabase run PlungeAI agents over the rows of a table or a dataframe. None exists today. The nearest path today is calling `POST /v1/agents/:id/execute` from a UDF or an edge function, or the models plane. ## Use this today Planned. Planned. Planned. Planned. Planned. Planned. Enrich a list of rows with a workflow you can run today. # Apache Spark Source: https://docs-preview.plungeai.com/data-integrations/spark Planned: not available yet. Tracked as TI-43. ## What this will do The Apache Spark integration will provide SQL-native UDFs that call PlungeAI agents. It does not exist yet. The nearest path today is calling `POST /v1/agents/:id/execute` from a UDF or an edge function, or the models plane. ## Use this today Enrich a list of rows with a workflow you can run today. # DuckDB Source: https://docs-preview.plungeai.com/data-integrations/duckdb Planned: not available yet. Tracked as TI-43. ## What this will do The DuckDB integration will provide batch enrichment from DuckDB queries. It does not exist yet. The nearest path today is calling `POST /v1/agents/:id/execute` from a UDF or an edge function, or the models plane. ## Use this today Enrich a list of rows with a workflow you can run today. # Google BigQuery Source: https://docs-preview.plungeai.com/data-integrations/bigquery Planned: not available yet. Tracked as TI-43. ## What this will do The Google BigQuery integration will provide BigQuery remote functions that call PlungeAI agents. It does not exist yet. The nearest path today is calling `POST /v1/agents/:id/execute` from a UDF or an edge function, or the models plane. ## Use this today Enrich a list of rows with a workflow you can run today. # Polars Source: https://docs-preview.plungeai.com/data-integrations/polars Planned: not available yet. Tracked as TI-43. ## What this will do The Polars integration will provide a Polars expression plugin that calls PlungeAI agents. It does not exist yet. The nearest path today is calling `POST /v1/agents/:id/execute` from a UDF or an edge function, or the models plane. ## Use this today Enrich a list of rows with a workflow you can run today. # Snowflake Source: https://docs-preview.plungeai.com/data-integrations/snowflake Planned: not available yet. Tracked as TI-43. ## What this will do The Snowflake integration will provide a Snowflake UDTF that calls PlungeAI agents. It does not exist yet. The nearest path today is calling `POST /v1/agents/:id/execute` from a UDF or an edge function, or the models plane. ## Use this today Enrich a list of rows with a workflow you can run today. # Supabase Source: https://docs-preview.plungeai.com/data-integrations/supabase Planned: not available yet. Tracked as TI-43. ## What this will do The Supabase integration will provide Supabase Edge Function helpers that call PlungeAI agents. It does not exist yet. The nearest path today is calling `POST /v1/agents/:id/execute` from a UDF or an edge function, or the models plane. ## Use this today Enrich a list of rows with a workflow you can run today. # PlungeAI API Glossary Source: https://docs-preview.plungeai.com/resources/glossary Planned: not available yet. Tracked as TI-74. ## What this will do Every term used across the API, MCP and skills docs. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Connector catalog Source: https://docs-preview.plungeai.com/resources/connector-catalog Planned: not available yet. Tracked as TI-74. ## What this will do OAuth and API-key connectors, BYOK, and how connected accounts reach calls. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Memory Source: https://docs-preview.plungeai.com/resources/memory Planned: not available yet. Tracked as TI-74. ## What this will do Long-term memory, and distilling sessions into skills. This page is not written yet; the source below covers the same material today. ## Use this today The section of the MCP developer guide this page will restate. # Roles and permissions Source: https://docs-preview.plungeai.com/resources/roles-and-permissions Planned: not available yet. Tracked as TI-74. ## What this will do Company and team roles, scopes and levels in the Dashboard. This page is not written yet; the source below covers the same material today. ## Use this today Teams, companies and roles live in Dashboard → Team and Dashboard → Workspace. # Trust fence and approvals Source: https://docs-preview.plungeai.com/resources/trust-fence Planned: not available yet. Tracked as TI-74. ## What this will do Key fences, the trust fence, the agent fence, mission bounds and model guardrails. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # API Error Codes and Warnings Source: https://docs-preview.plungeai.com/resources/warnings-and-errors Planned: not available yet. Tracked as TI-74. ## What this will do Every error envelope and code, the outcomes, and what to retry. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Webhook setup Source: https://docs-preview.plungeai.com/resources/webhook-setup Planned: not available yet. Tracked as TI-25. ## What this will do PlungeAI will call a URL you register when a workflow run finishes, signed so you can verify the sender, with retries on failure. Nothing sends outbound webhooks today. ## Use this today Follow a run live over SSE, or start it with sync:false and poll the results route. # Migrate from legacy execute aliases Source: https://docs-preview.plungeai.com/workflows/migration-guide Planned: not available yet. Tracked as TI-74. ## What this will do Move `/v1/execute` and `/v1/cnl/*` calls to `/v1/workflows/*`. This page is not written yet; the source below covers the same material today. ## Use this today The section of the One API developer guide this page will restate. # Docs for AI agents Source: https://docs-preview.plungeai.com/resources/docs-for-agents Partly available: the Docs MCP server, which will let your agent search and read these pages. Tracked as TI-35. Every page on docs.plungeai.com has a markdown form, the whole site has an index, and one file tells an agent how to connect PlungeAI. ## /agents.md [https://docs.plungeai.com/agents.md](/agents.md) is the setup file for coding agents: get an `ozk_` key from the user, connect the client to `https://mcp.plungeai.com/v1`, verify with `plungeai_whoami`, add the skills and follow the rules. Paste this prompt into any agent to run it: ```text Use curl to read https://docs.plungeai.com/agents.md and perform the setup to connect PlungeAI ``` It is served as `text/markdown; charset=utf-8`, and it is not a sidebar page. ## llms.txt and llms-full.txt | File | What it holds | |---|---| | [/llms.txt](/llms.txt) | `# PlungeAI`, a one-line description, then one bullet per page in sidebar order (`[Title](https://docs.plungeai.com/.md): description`), with ` (planned)` after pages that are not available yet; then `## OpenAPI Specs` and `## Optional` | | [/llms-full.txt](/llms-full.txt) | Every page in full: `# `, a `Source:` line with the page URL, then the page body; API and MCP reference pages in a condensed form | ## Markdown twins Append `.md` to any page URL, for example [/getting-started/quickstart.md](/getting-started/quickstart.md), or request the page with `Accept: text/markdown`: ```bash curl -s -H 'Accept: text/markdown' https://docs.plungeai.com/getting-started/quickstart ``` A twin starts with a pointer to `/llms.txt`, then the page title and description, then the page source unchanged. Twins carry `X-Robots-Tag: noindex`, so search engines index the HTML page only. ## Docs MCP A docs MCP server at `docs.plungeai.com/mcp` will let an agent search these docs and read a page by path. It is planned (TI-35) and answers with a JSON-RPC error until then. The product MCP server at `https://mcp.plungeai.com/v1` is a different server and is live. <Card title="Docs MCP server" icon="plug" href="/developer-tools/mcp/docs-mcp"> What the docs MCP server will do. </Card> ## Other llms.txt files | URL | Covers | |---|---| | https://api.plungeai.com/llms.txt | The One API guide | | https://mcp.plungeai.com/llms.txt | Workflow authoring over MCP (the CNL skill) | | https://skills.plungeai.com/llms.txt | The agent skills catalog | # Status Source: https://docs-preview.plungeai.com/resources/status <Info> Planned: not available yet. Tracked as TI-29. </Info> ## What this will do A status page will show the health and incident history of each PlungeAI service. There is no status page today; the health endpoints below answer directly. ## Health endpoints today | Service | URL | |---|---| | One API | https://api.plungeai.com/health | | MCP server | https://mcp.plungeai.com/health and https://mcp.plungeai.com/v1/info | | Models gateway | https://gateway.plungeai.com/health | | Skills site | https://skills.plungeai.com/health | | Landing site | https://plungeai.com/health | ## Use this today <Card title="FAQs" icon="message" href="/resources/faqs"> Answers to common questions. </Card> <!-- placeholder-source: content/_placeholders.json --> # FAQs Source: https://docs-preview.plungeai.com/resources/faqs <Info> Planned: not available yet. Tracked as TI-74. </Info> ## What this will do Answers to common platform, API, billing and security questions. This page is not written yet; the source below covers the same material today. ## Use this today <Card title="MCP guide: 15.1 Five first checks" icon="book" href="https://mcp.plungeai.com/docs#151-five-first-checks"> The section of the MCP developer guide this page will restate. </Card> <!-- placeholder-source: content/_placeholders.json --> # Create chat completion Source: https://docs-preview.plungeai.com/api-reference/models/create-chat-completion openapi.json post /v1/chat/completions Send messages to a model and get a completion, or stream it as SSE chunks. Ordered fallback with `models[]`, `sort`, presets and an opt-in response cache. # Create embeddings Source: https://docs-preview.plungeai.com/api-reference/models/create-embeddings openapi.json post /v1/embeddings Turn a string or a list of strings into embedding vectors (OpenAI-compatible). # List models Source: https://docs-preview.plungeai.com/api-reference/models/list-models openapi.json get /v1/models The priced model catalog routing candidates are drawn from. `pricing.in` and `pricing.out` are the provider cost basis in USD per 1M tokens, before your org markup. # Search the registry Source: https://docs-preview.plungeai.com/api-reference/discovery/search-registry openapi.json get /v1/discovery/search Hybrid semantic and keyword search over capability cards. Pages with `limit` and `offset`; a page shorter than `limit` is the last one. # Recommend a card Source: https://docs-preview.plungeai.com/api-reference/discovery/recommend-card openapi.json post /v1/discovery/recommend Get the one best capability card for a task, with a score. # Get a card Source: https://docs-preview.plungeai.com/api-reference/discovery/get-card openapi.json get /v1/discovery/cards/{type}/{id} Read one capability card as markdown (the LLM view): operations, examples and "Not for" redirects. # List tools Source: https://docs-preview.plungeai.com/api-reference/tools/list-tools openapi.json get /v1/tools List the active tool agents, 50 per page by default (at most 100). # Get a tool contract Source: https://docs-preview.plungeai.com/api-reference/tools/get-tool-contract openapi.json get /v1/tools/{id} The invocation contract of one tool agent: JSON Schema parameters, operations, approval gates and examples. # Execute a tool Source: https://docs-preview.plungeai.com/api-reference/tools/execute-tool openapi.json post /v1/tools/{id}/execute Run one operation of a tool agent with typed params. Gated and money verbs refuse unattended calls. # List agents Source: https://docs-preview.plungeai.com/api-reference/agents/list-agents openapi.json get /v1/agents List the active agents, 50 per page by default (at most 100). # List agent categories Source: https://docs-preview.plungeai.com/api-reference/agents/list-agent-categories openapi.json get /v1/agents/categories Agent categories with the number of active agents in each. # Execute an agent Source: https://docs-preview.plungeai.com/api-reference/agents/execute-agent openapi.json post /v1/agents/{id}/execute Run one agent with a prompt. Sync by default; `sync: false` returns a pointer to redeem later; `stream: true` streams OpenAI-shaped chunks. # Get an agent result Source: https://docs-preview.plungeai.com/api-reference/agents/get-agent-result openapi.json get /v1/agents/results/{workflowId}/{taskId} Redeem the result of an async agent run with the `workflow_id` and `task_id` it returned. # Execute an inline workflow Source: https://docs-preview.plungeai.com/api-reference/workflows/execute-inline-workflow openapi.json post /v1/workflows/execute Run a CNL workflow sent in the body, as JSON `{workflow, input}` or as a raw `text/yaml` document. Returns a pointer; read the content from the result route. # Stream an inline workflow Source: https://docs-preview.plungeai.com/api-reference/workflows/stream-inline-workflow openapi.json post /v1/workflows/execute-stream Run an inline workflow and stream every engine event as SSE until `workflow_completed` or `workflow_error`. # Execute a saved workflow Source: https://docs-preview.plungeai.com/api-reference/workflows/execute-saved-workflow openapi.json post /v1/workflows/{id}/execute Run one of your saved workflows by id with an optional `input` or `inputs`. # Stream a saved workflow Source: https://docs-preview.plungeai.com/api-reference/workflows/stream-saved-workflow openapi.json post /v1/workflows/{id}/execute-stream Run a saved workflow and stream its engine events as SSE. # Get a workflow result Source: https://docs-preview.plungeai.com/api-reference/workflows/get-workflow-result openapi.json get /v1/workflows/results/{workflowId}/{taskId} Read the stored output of one task of a run, usually the `final_task_id` the execute call returned. # Cancel an execution Source: https://docs-preview.plungeai.com/api-reference/workflows/cancel-execution openapi.json post /v1/workflows/executions/{id}/cancel Ask a running execution of yours to stop. Cancellation is cooperative. # List MCP tools Source: https://docs-preview.plungeai.com/api-reference/mcp/list-mcp-tools openapi.json get /v1/mcp/tools The MCP server tool list as a plain GET; the answer is the JSON-RPC `tools/list` envelope with the tools under `result.tools`. # MCP endpoint (JSON-RPC) Source: https://docs-preview.plungeai.com/api-reference/mcp/mcp-endpoint openapi.json post /v1/mcp The Streamable HTTP MCP endpoint: `initialize`, then `tools/list` and `tools/call`. The samples use the MCP host `https://mcp.plungeai.com/v1`, the same server. # Open an MCP run Source: https://docs-preview.plungeai.com/api-reference/mcp/create-mcp-run openapi.json post /v1/mcp/runs Connect catalog MCP servers for a run and get their namespaced tool table. Always close the run when done. # List MCP run tools Source: https://docs-preview.plungeai.com/api-reference/mcp/list-mcp-run-tools openapi.json get /v1/mcp/runs/{id}/tools List the namespaced tools (`mcp__<server>__<tool>`) of an open MCP run. # Call an MCP run tool Source: https://docs-preview.plungeai.com/api-reference/mcp/call-mcp-run-tool openapi.json post /v1/mcp/runs/{id}/call Call one namespaced tool of an open MCP run with its arguments. # Close an MCP run Source: https://docs-preview.plungeai.com/api-reference/mcp/close-mcp-run openapi.json delete /v1/mcp/runs/{id} Close an MCP run and drop its state. Idempotent. # Get a trace Source: https://docs-preview.plungeai.com/api-reference/traces/get-trace openapi.json get /v1/traces/{id} The persisted trace of one run: execution spans and the gateway request log for the trace id. # Health Source: https://docs-preview.plungeai.com/api-reference/meta/health openapi.json get /health Liveness probe of the One API router. No key needed. # OpenAPI spec Source: https://docs-preview.plungeai.com/api-reference/meta/get-openapi-spec openapi.json get /v1/openapi.json The OpenAPI 3.1 document of the One API. The docs copy with tags is at [/openapi.json](/openapi.json). # llms.txt Source: https://docs-preview.plungeai.com/api-reference/meta/llms-txt <Note> Not in the OpenAPI spec; documented from the route code. </Note> ```text Endpoint GET https://api.plungeai.com/llms.txt ``` `GET https://api.plungeai.com/llms.txt` returns the index of the One API Developer Guide in the [llmstxt.org](https://llmstxt.org) format, so an AI coding agent can onboard from the domain alone. No key is needed. ## Response <ResponseField name="200" type="text/plain"> The guide index. Cached for 5 minutes (`Cache-Control: public, max-age=300`). </ResponseField> ## Example <CodeGroup> ```python Python import requests print(requests.get('https://api.plungeai.com/llms.txt').text) ``` ```typescript TypeScript const res = await fetch('https://api.plungeai.com/llms.txt') console.log(await res.text()) ``` ```java Java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class Main { public static void main(String[] args) throws Exception { HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.plungeai.com/llms.txt")).GET().build(); HttpResponse<String> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString()); System.out.println(res.body()); } } ``` ```bash cURL curl -s https://api.plungeai.com/llms.txt ``` </CodeGroup> The index of this documentation site is [/llms.txt](/llms.txt) on docs.plungeai.com. # llms-full.txt Source: https://docs-preview.plungeai.com/api-reference/meta/llms-full-txt <Note> Not in the OpenAPI spec; documented from the route code. </Note> ```text Endpoint GET https://api.plungeai.com/llms-full.txt ``` `GET https://api.plungeai.com/llms-full.txt` returns the full One API Developer Guide 3.0 as one markdown document, for agents that read everything at once. No key is needed. ## Response <ResponseField name="200" type="text/markdown; charset=utf-8"> The full guide. Cached for 5 minutes (`Cache-Control: public, max-age=300`). </ResponseField> ## Example <CodeGroup> ```python Python import requests open('one-api-guide.md', 'w').write(requests.get('https://api.plungeai.com/llms-full.txt').text) ``` ```typescript TypeScript const res = await fetch('https://api.plungeai.com/llms-full.txt') console.log((await res.text()).length) ``` ```java Java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.file.Path; public class Main { public static void main(String[] args) throws Exception { HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.plungeai.com/llms-full.txt")).GET().build(); HttpResponse<Path> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofFile(Path.of("one-api-guide.md"))); System.out.println(res.statusCode() + " " + res.body()); } } ``` ```bash cURL curl -s https://api.plungeai.com/llms-full.txt -o one-api-guide.md ``` </CodeGroup> The full text of this documentation site is [/llms-full.txt](/llms-full.txt) on docs.plungeai.com. # Guide (HTML) Source: https://docs-preview.plungeai.com/api-reference/meta/docs <Note> Not in the OpenAPI spec; documented from the route code. </Note> ```text Endpoint GET https://api.plungeai.com/docs ``` `GET https://api.plungeai.com/docs` serves the One API Developer Guide 3.0 as a single HTML page. The same guide is copied to `plungeai.com/docs`. No key is needed. ## Response <ResponseField name="200" type="text/html"> The guide page. Cached for 5 minutes (`Cache-Control: public, max-age=300`). </ResponseField> ## Example <CodeGroup> ```python Python import requests open('one-api-guide.html', 'w').write(requests.get('https://api.plungeai.com/docs').text) ``` ```typescript TypeScript const res = await fetch('https://api.plungeai.com/docs') console.log(res.status, (await res.text()).length) ``` ```java Java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.file.Path; public class Main { public static void main(String[] args) throws Exception { HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.plungeai.com/docs")).GET().build(); HttpResponse<Path> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofFile(Path.of("one-api-guide.html"))); System.out.println(res.statusCode() + " " + res.body()); } } ``` ```bash cURL curl -s -o one-api-guide.html https://api.plungeai.com/docs ``` </CodeGroup> This site replaces the single page with one page per topic; start at the [overview](/getting-started/overview). # Resolve a task to one tool, its operation and an example call, with a… Source: https://docs-preview.plungeai.com/api-reference/other/post-v1-discovery-resolve openapi.json post /v1/discovery/resolve Resolve a task to one tool, its operation and an example call, with a calibrated confidence # MCP server overview Source: https://docs-preview.plungeai.com/mcp-reference/overview The PlungeAI MCP server exposes 20 `plungeai_*` tools, one prompt, five resources and three resource templates to any MCP client. This tab documents every tool, resource and protocol method: the tool, resource and prompt pages are generated from the server code; this overview and the protocol pages are written from the MCP guide. ## Endpoint | Item | Value | |---|---| | URL | `https://mcp.plungeai.com/v1` (`/v1/` answers the same) | | Legacy path | `/mcp` on the same host still answers with the same handler; configure `/v1` | | Methods | `POST` with JSON-RPC 2.0. `GET` and `DELETE` without a session answer `405` | | Request headers | `Authorization: Bearer $PLUNGE_API_KEY` or `X-API-Key: $PLUNGE_API_KEY`, `Content-Type: application/json`, `Accept: application/json, text/event-stream` | | Responses | `application/json`; `tools/call` answers as `text/event-stream`; a notification alone answers `202` with no body | <Note> The docs site's own MCP server (`docs.plungeai.com/mcp`, planned as TI-35) is a different server. Its resources use the `plungeai-docs://` scheme, so they never collide with this server's `plungeai://` URIs. </Note> ## Versions The server version is `2.5.1` and it implements MCP revision `2025-11-25`. It negotiates down to `2024-11-05`: a client that sends `2025-06-18`, `2025-03-26`, `2024-11-05` or `2024-10-07` in `initialize` gets that version back, and any other value gets `2025-11-25`. After `initialize` you may send `MCP-Protocol-Version`; an unsupported value answers `400`, and leaving the header out is fine. See [initialize](/mcp-reference/protocol/initialize). <!-- SERVER_VERSION and PROTOCOL_VERSION: orchestration/mcp-gateway/server.ts:75-80. --> ## Authentication and key fences Every request needs an `ozk_` key, `tools/list` included; create one at **Dashboard → One API → Keys**. Key fences are set by PlungeAI on request. A key fenced to some tools does not see the others in `tools/list`, and a `tools/call` to one of them answers JSON-RPC `-32602` `Tool not permitted for this key: <name>`. Check your identity and tier with [plungeai_whoami](/mcp-reference/tools/plungeai_whoami). ## Stateless requests and sessions Each `POST` gets a fresh server instance and stands alone: no `Mcp-Session-Id` is issued and none is needed. Because nothing is kept between requests, `notifications/tools/list_changed` is never sent, `logging/setLevel` is not persisted and a dropped `tools/call` stream is not replayed (the run keeps going; read it with `plungeai_get_result`). Stateful sessions exist only on keys PlungeAI issues with sessions enabled: `initialize` then returns an `Mcp-Session-Id` header to send on every later request, and a session expires after 10 minutes without a request. ## Batches A JSON array of messages is answered as an array, one answer per message: ```bash 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":"ping"},{"jsonrpc":"2.0","id":2,"method":"prompts/list"}]' ``` A batch that contains `initialize` with other messages answers `400 -32600`, and a batch with a `tools/call` is answered as SSE. ## Ignored and rejected methods | Method | What happens | |---|---| | `notifications/cancelled` | Ignored: `202`. To stop a run, call `plungeai_executions` with `{"action":"cancel"}` | | `resources/subscribe`, `resources/unsubscribe`, `completion/complete` | Rejected: `-32601 Method not found` | | Any other method | Rejected: `-32601 Method not found` | The server never sends requests to your client: no sampling, elicitation or roots. ## Errors Protocol errors mean the request never reached a tool. The body is always `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 400 | `-32700` | The body is not valid JSON, or not a JSON-RPC message | | 400 | `-32600` | A batch holding `initialize` plus other messages | | 400 | `-32000` | An unsupported `MCP-Protocol-Version` header after `initialize` | | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | | 404 | `-32001` | An `Mcp-Session-Id` that is unknown or expired | | 405 | `-32000` | `GET` or `DELETE` without a session | | 413 | `-32600` | A body over 1 MiB | | 415 | `-32000` | A complete `Accept` header with a non-JSON `Content-Type` | | 429 | `-32000` | Rate limit reached; `Retry-After` and `error.data.retryAfter` give the seconds | | 200 | `-32602` | Unknown tool, a tool your key is fenced from, malformed `initialize` params, or an unknown prompt | | 200 | `-32002` | `resources/read` for an unknown resource, workflow or execution | | 200 | `-32601` | A method the server does not implement | | 500 | `-32603` | An unhandled server error | Tool failures are not protocol errors: execution tools answer with an outcome (`ok`, `needs_input`, `needs_connection`, `needs_api_key`, `needs_approval`, `unavailable` or `error`) inside a normal result. ## Helper routes | Route | Key | Returns | |---|---|---| | `GET https://mcp.plungeai.com/v1/info` | no | Server name `plungeai.com`, version, protocol version and capabilities | | `GET https://mcp.plungeai.com/health` | no | Dependency probes; `200` when healthy, `503` when one fails | ## Recurring parameters Two arguments appear on many tool pages and mean the same thing everywhere: | Argument | On | Meaning | |---|---|---| | `user_request` | Every tool | The user's request in their own words, up to 4,000 characters, optional. Always send it: the platform uses it for context and routing | | `format` | Nine tools | `markdown` (the default) or `json`; `json` returns the same answer as a JSON document and as `structuredContent` | # plungeai_execute_workflow Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_execute_workflow Execute a CNL workflow (saved workflow_id or ad-hoc workflow_yaml). Streams progress. Use mode:"async" for long runs (>3 min) — it returns an execution_id to poll with plungeai_get_workflow_status. In ad-hoc YAML, write long strings as block scalars (`prompt: |`) — never hard-wrap a value; structured tool-agents take their card's parameters as task fields alongside `agent:`. Always answers with a structured outcome (never a raw error) — follow the remediation instead of retrying the identical call. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `workflow_yaml` | string | no | — | Ad-hoc CNL workflow YAML. The `workflow:` wrapper is optional — bare top-level name/tasks is accepted and wrapped automatically. | | `workflow_id` | string | no | — | | | `input` | string | no | — | | | `inputs` | object | no | — | | | `mode` | enum<string> | no | sync | | | `format` | enum<string> | no | markdown | markdown (default): rendered for an AI reader · json: the same outcome as a JSON document in `text` plus `structuredContent` | # plungeai_execute_agent Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_execute_agent Execute a single PROMPT-DRIVEN agent (e.g. "llm-agent", or "skill-agent" with a persona). Pass session_id to start/continue a conversational agent. Structured tool-agents (cards with a Parameters table, e.g. markitdown, weather-agent) take typed fields, not prose — use plungeai_get_tool_contract + plungeai_execute_tool for those. Always answers with a structured outcome (never a raw error) — follow the remediation instead of retrying the identical call. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `agent` | string | yes | — | | | `prompt` | string | yes | — | | | `persona` | string | no | — | | | `model` | string | no | the agent's default | | | `provider` | string | no | the model's catalog provider | | | `maxTokens` | integer | no | — | | | `max_tokens` | integer | no | — | | | `temperature` | number | no | — | | | `top_p` | number | no | — | | | `reasoning_effort` | enum<string> | no | — | | | `thinking_level` | string | no | — | | | `streaming` | boolean | no | true | | | `session_id` | string | no | — | | | `format` | enum<string> | no | markdown | markdown (default): rendered for an AI reader · json: the same outcome as a JSON document in `text` plus `structuredContent` | # plungeai_get_tool_contract Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_get_tool_contract The exact invocation contract for one registry agent: JSON Schema for its parameters, operations (with approval gates), worked YAML examples, output shape, and LIVE credential status for the acting user (platform-managed vs "connect Google first"). Fetch this before the first plungeai_execute_tool call to an unfamiliar agent — the contract IS the API docs. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `agent_id` | string | yes | — | | | `format` | enum<string> | no | markdown | markdown (default): rendered for an AI reader · json: the same outcome as a JSON document in `text` plus `structuredContent` | # plungeai_execute_tool Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_execute_tool Execute one structured tool-agent directly with typed params: {agent_id, operation?, params}. Runs through the engine with full observability; use mode:"async" for long runs. Always answers with a structured outcome (never a raw error): ok → result; needs_input → missing fields + the schema; needs_connection/needs_api_key → tell the user exactly what to connect in our apps, then retry; needs_approval → relay the ⏸ block and use plungeai_continue after the user decides; unavailable → real alternatives. Follow the remediation — do not retry the identical call blind. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `agent_id` | string | yes | — | | | `operation` | string | no | the card's default operation | | | `params` | object | no | {} | | | `prompt` | string | no | — | | | `mode` | enum<string> | no | sync | | | `format` | enum<string> | no | markdown | markdown (default): rendered for an AI reader · json: the same outcome as a JSON document in `text` plus `structuredContent` | # plungeai_run_mission Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_run_mission Run a bounded autonomous agent mission (loop agent): give a goal, optional tool fence and iteration cap. Recalls and writes long-term memory automatically. Defaults to async — poll plungeai_get_workflow_status. Always answers with a structured outcome (never a raw error) — follow the remediation instead of retrying the identical call. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `goal` | string | yes | — | | | `mission` | string | no | You are a capable autonomous agent. Achieve the goal thoroughly and cite sources. | | | `allowed_tools` | string[] | no | ["web_search", "web_fetch", "task_complete"] | | | `max_iterations` | integer | no | 8 | | | `success_criteria` | string[] | no | — | | | `persona` | string | no | — | | | `skills` | string[] | no | — | | | `mode` | enum<string> | no | async | | # plungeai_learn Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_learn Manage your private skill library. `action: learn` (default) distills a URL, PDF text, or a past workflow into a reusable skill via the `learn` pre-built agent (needs `source`; defaults to async — poll plungeai_get_workflow_status). `action: list` returns your learned skills (id + summary). `action: forget` deletes one by `name` (the id from list). Always answers with a structured outcome (never a raw error) — follow the remediation instead of retrying the identical call. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `action` | enum<string> | no | learn | learn (default): distill source into a skill · list: your learned skills · forget: delete one (name required) | | `source` | string | no | — | A URL, or text/markdown to distill, or a description of what you just did. | | `name` | string | no | picked automatically on learn | Skill id (kebab-case): picked automatically on learn, required on forget. | | `mode` | enum<string> | no | async | | # plungeai_list_agents Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_list_agents Discover platform building-block agents from the live registry (the capability catalog). NOT the user's own agents — for "show me my agents/workflows" use plungeai_list_workflows. `search` is a hybrid semantic+keyword query — describe the capability in natural language (e.g. "web search", "pdf to markdown"). Prefer search/category filters; an unfiltered list returns the whole catalog (~90 agents, large). The catalog is active-only, and execution refuses any id that is not active — so take ids from here, not from memory. Fetch one full card with agent_id. With `format: "json"` the result is `{content: <markdown>}` — its source is rendered registry markdown; typed rows are a follow-up. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `search` | string | no | — | | | `category` | string | no | — | | | `agent_id` | string | no | — | | | `kind` | enum<string> | no | agents | | | `limit` | integer | no | 25 with search or category, 100 without | | | `format` | enum<string> | no | markdown | markdown (default): rendered for an AI reader · json: the same outcome as a JSON document in `text` plus `structuredContent` | # plungeai_list_workflows Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_list_workflows List your saved workflows — what users usually mean by "my agents". No args shows your folders (rubrics) + recent; filter with folder and/or search. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `search` | string | no | — | | | `folder` | string | no | — | | | `limit` | integer | no | 50 | | | `format` | enum<string> | no | markdown | markdown (default): rendered for an AI reader · json: the same outcome as a JSON document in `text` plus `structuredContent` | # plungeai_get_result Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_get_result Retrieve the result of one of your executions (by `execution_id`) — for conversational runs this includes the FULL conversation thread (all follow-up turns), same as Studio shows. Pass task_id to read a single task's output (e.g. one branch of a workflow) instead of the final result. The output is final user-ready markdown: show it to the user verbatim and complete — never summarize or re-type it. With `format: "json"` the result is `{content: <markdown>}` — an assembled multi-store document rendered as markdown; typed rows are a follow-up. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `execution_id` | string | no | — | | | `workflow_id` | string | no | — | | | `task_id` | string | no | the final task | | | `format` | enum<string> | no | markdown | markdown (default): rendered for an AI reader · json: the same outcome as a JSON document in `text` plus `structuredContent` | # plungeai_get_workflow_status Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_get_workflow_status Check the status of one of your executions (self-heals stuck runs). Returns structured content too, including `continuation` when the run is paused awaiting user approval or an answer — relay that to the user and use plungeai_continue. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `execution_id` | string | yes | — | | # plungeai_workflow Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_workflow Manage your workflows: action create|get|update|delete|save_version|list_versions|get_version|restore_version. Create/update/delete sync live to Studio, iMini, and peer apps. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `action` | enum<string> | yes | — | | | `workflow_id` | string | no | — | | | `name` | string | no | — | | | `yaml` | string | no | — | | | `description` | string | no | — | | | `folder` | string | no | — | | | `kind` | enum<string> | no | workflow on create | | | `version_id` | string | no | — | | | `version_description` | string | no | — | | # plungeai_executions Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_executions Browse your execution history: action list|get|output|conversation|delete|cancel. `cancel` stops a running execution (cooperative — it stops at its next turn or tool boundary). Outputs are final user-ready markdown (tables, threads): show them to the user verbatim and complete — never summarize or re-type them. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `action` | enum<string> | yes | — | | | `execution_id` | string | no | — | | | `workflow_id` | string | no | — | | | `limit` | integer | no | 20 | | | `offset` | integer | no | 0 | | | `format` | enum<string> | no | markdown | markdown (default): rendered for an AI reader · json: the same outcome as a JSON document in `text` plus `structuredContent` | # plungeai_followup Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_followup Ask a follow-up about a completed execution (continues its agent session or researches with prior context). If the execution is still running, your message is queued and injected at its next turn (steer); if finished, it continues the conversation. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `execution_id` | string | yes | — | | | `prompt` | string | yes | — | | # plungeai_continue Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_continue Continue a paused conversation: answer a question (message) or approve a pending action (approve:true). Only pass approve:true after the user explicitly confirmed — never approve on your own. To deny or change course, pass their words as message. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `execution_id` | string | yes | — | | | `message` | string | no | — | | | `approve` | boolean | no | — | | # plungeai_chat Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_chat Persistent chat with the PlungeAI assistant (platform tools + web search). action send|new|list_sessions|history. Conversations appear in Studio and the CLI. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `action` | enum<string> | yes | — | | | `message` | string | no | — | | | `conversation_id` | string | no | a new conversation (send) | | # plungeai_build_workflow Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_build_workflow Generate a new workflow from a goal, or refine an existing one (workflow_id + instruction), via the platform builder. Saves it so it appears everywhere (live sync). | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `goal` | string | no | — | | | `workflow_id` | string | no | — | | | `instruction` | string | no | — | | # plungeai_memory Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_memory Long-term memory scoped to you: action recall|remember|search_runs|get_run. remember writes the durable store that recall reads (target user|memory, operation add|replace|remove|read) — use it when the user asks to remember something. Past-run history is separate: search_runs/get_run read the run journal, which recall deliberately does not include. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `action` | enum<string> | yes | — | | | `query` | string | no | — | | | `run_id` | string | no | — | | | `target` | enum<string> | no | memory | | | `operation` | enum<string> | no | add | | | `content` | string | no | — | | | `old_text` | string | no | — | | | `limit` | integer | no | 10 | | # plungeai_templates Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_templates Workflow templates: action list|get|use. "use" creates a workflow from the template (optional name + folder). | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `action` | enum<string> | yes | — | | | `template_id` | string | no | — | | | `category` | string | no | — | | | `name` | string | no | <template name> (copy); a bot template keeps its own name | | | `folder` | string | no | — | | | `limit` | integer | no | 50 | | # plungeai_schedule Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_schedule Scheduled (cron) jobs: action stats|list|get|create|update|pause|resume|delete|run_now|runs. create needs name, job_type (agent|query|workflow|heartbeat), target, schedule; create also takes mission_ref (schedule a pre-built agent card). | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `action` | enum<string> | yes | — | | | `job_id` | string | no | — | | | `name` | string | no | — | | | `description` | string | no | — | | | `job_type` | enum<string> | no | — | | | `target` | string | no | — | | | `schedule` | string | no | — | | | `timezone` | string | no | UTC | | | `parameters` | object | no | — | Job extras. deliver: DeliverTarget[] — objects {channel: "inapp"\|"email"\|"slack"\|"telegram"\|"whatsapp"\|"discord", chat_id?, to?}; bare {channel:"slack"} DMs the owner, bare {channel:"email"} mails the owner's registered address, other emails must be confirmed recipients. prompt: per-run goal. | | `limit` | integer | no | 50 for list, 20 for runs | | | `mission_ref` | string | no | — | | | `check_agent` | string | no | — | | | `condition_prompt` | string | no | — | | | `trigger_workflow` | string | no | — | | | `notify_channel` | enum<string> | no | — | | | `notify_chat_id` | string | no | — | | # plungeai_whoami Source: https://docs-preview.plungeai.com/mcp-reference/tools/plungeai_whoami Show the authenticated identity: user id, tier, key label, rate-limit window. | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `user_request` | string | no | — | The user's original request, verbatim and in their own words, before you translated it into this call. Always include it — the platform uses it for request context, routing and support diagnostics. | | `format` | enum<string> | no | markdown | markdown (default): rendered for an AI reader · json: the same outcome as a JSON document in `text` plus `structuredContent` | # PlungeAI Agents Source: https://docs-preview.plungeai.com/mcp-reference/resources/agents-list `plungeai://agents/list` · `text/markdown` · `static` The live registry of **active** agents: `kind=agents&status=active&format=md&limit=100`. The Markdown starts `# Registry search`, then `*<n> results*`. Each agent follows under a `## Name (id)` heading with its kind, category and status line, its description and a **Good at** list. On 2026-09-24 the registry listed **92** active agents (live-verified). The listing is large, about 150 KB, so attach it only when you really want the whole catalog. For a normal question, a filtered `plungeai_list_agents` search is far smaller. ```bash # verify # expect: Registry search # expect: status:active 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":6,"method":"resources/read","params":{"uri":"plungeai://agents/list"}}' \ | cut -c1-1200 ``` ## Result shape `resources/read` answers one entry: ```json { "contents": [ { "uri": "plungeai://agents/list", "mimeType": "text/markdown", "text": "…" } ] } ``` ## Errors `resources/read` answers JSON-RPC errors, not outcomes; the SDK prefixes each message with `MCP error <code>:` ([resources/read](/mcp-reference/protocol/resources-read)). - `-32603` `Registry error <status>`: the registry answered with a non-2xx status. - `-32002` `Resource not found: <uri>`: the URI matches no resource or template. # Agent Categories Source: https://docs-preview.plungeai.com/mcp-reference/resources/agents-categories `plungeai://agents/categories` · `text/markdown` · `static` Active agents (up to 500) grouped by category into one table, largest first. An agent with no category counts as `general`: ``` # Agent Categories (<n> agents, live registry) | Category | Agents | |:---|---:| | google-workspace | … | … _Read `plungeai://agents/{category}` for the agents in one category._ ``` This is the cheap way to answer "what kinds of agents are there". On 2026-09-24 the registry held 92 active agents in 14 categories (live-verified): `google-workspace`, `tools`, `search`, `microsoft-365`, `ai`, `blockchain`, `communication`, `ecommerce-agents`, `payment`, `entertainment`, `media`, `financials`, `shopping`, `coding-agents`. Note the finance category is `financials`, not `finance`. ```bash # verify # expect: Agent Categories # expect: | Category | Agents | 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":7,"method":"resources/read","params":{"uri":"plungeai://agents/categories"}}' ``` ## Result shape `resources/read` answers one entry: ```json { "contents": [ { "uri": "plungeai://agents/categories", "mimeType": "text/markdown", "text": "…" } ] } ``` ## Errors `resources/read` answers JSON-RPC errors, not outcomes; the SDK prefixes each message with `MCP error <code>:` ([resources/read](/mcp-reference/protocol/resources-read)). - `-32603` `Registry error <status>`: the registry answered with a non-2xx status. - `-32002` `Resource not found: <uri>`: the URI matches no resource or template. # Personas Source: https://docs-preview.plungeai.com/mcp-reference/resources/personas-list `plungeai://personas/list` · `text/markdown` · `static` The persona registry: `kind=personas&format=md&limit=100`, as registry Markdown (a `## Name (id)` heading per persona, its kind and category, **Good at**). Unlike the agent resources, it has **no** `status:active` filter, because no persona card carries that tag and the filter would empty the list (`resources.ts`). The list stops at 100: on 2026-09-24 the registry answered `*100 results*`. For a specific persona, search with `plungeai_list_agents` `{"kind":"personas","search":"…"}`. A persona id goes on `plungeai_execute_agent` `persona` or a mission's `persona` ([Agents & missions](https://mcp.plungeai.com/docs#7-agents--missions)). ```bash # verify # expect: Registry search 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":8,"method":"resources/read","params":{"uri":"plungeai://personas/list"}}' \ | cut -c1-800 ``` ## Result shape `resources/read` answers one entry: ```json { "contents": [ { "uri": "plungeai://personas/list", "mimeType": "text/markdown", "text": "…" } ] } ``` ## Errors `resources/read` answers JSON-RPC errors, not outcomes; the SDK prefixes each message with `MCP error <code>:` ([resources/read](/mcp-reference/protocol/resources-read)). - `-32603` `Registry error <status>`: the registry answered with a non-2xx status. - `-32002` `Resource not found: <uri>`: the URI matches no resource or template. # Your Workflows Source: https://docs-preview.plungeai.com/mcp-reference/resources/workflows-list `plungeai://workflows/list` · `text/markdown` · `static` **Your workflows**: the 50 most recently updated saved workflows on your account (what users call "my agents"). One bullet each (bold name, the id as code, then the description) under `# Your Workflows (<n>)`. With no saved workflows, the text is `_No workflows yet._`. It carries no folders and no search. For those, use `plungeai_list_workflows`. ```bash # verify # expect: "uri":"plungeai://workflows/list" 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":9,"method":"resources/read","params":{"uri":"plungeai://workflows/list"}}' ``` ## Result shape `resources/read` answers one entry: ```json { "contents": [ { "uri": "plungeai://workflows/list", "mimeType": "text/markdown", "text": "…" } ] } ``` ## Errors `resources/read` answers JSON-RPC errors, not outcomes; the SDK prefixes each message with `MCP error <code>:` ([resources/read](/mcp-reference/protocol/resources-read)). - `-32002` `Resource not found: <uri>`: the URI matches no resource or template. # Workflow Authoring Guide Source: https://docs-preview.plungeai.com/mcp-reference/resources/docs-workflow-authoring `plungeai://docs/workflow-authoring` · `text/markdown` · `static` The complete CNL workflow-authoring skill as one Markdown document: how to author, validate and save CNL workflows, with examples. It is a static bundle built into the server and needs no data access. The content is identical to `GET https://mcp.plungeai.com/llms-full.txt`, which needs no key (61,309 bytes on 2026-09-24, live-verified). Attach it when you want your client to write CNL YAML by hand ([Workflows](https://mcp.plungeai.com/docs#8-workflows)). The same skill is in the catalog at `https://skills.plungeai.com`. ```bash # verify # expect: PlungeAI Workflow Authoring 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":10,"method":"resources/read","params":{"uri":"plungeai://docs/workflow-authoring"}}' \ | cut -c1-600 ``` ## Result shape `resources/read` answers one entry: ```json { "contents": [ { "uri": "plungeai://docs/workflow-authoring", "mimeType": "text/markdown", "text": "…" } ] } ``` ## Errors `resources/read` answers JSON-RPC errors, not outcomes; the SDK prefixes each message with `MCP error <code>:` ([resources/read](/mcp-reference/protocol/resources-read)). - `-32002` `Resource not found: <uri>`: the URI matches no resource or template. # Agents by category Source: https://docs-preview.plungeai.com/mcp-reference/resources/agents-by-category `plungeai://agents/{category}` · `text/markdown` · `template` The active agents in one category, up to 100, as registry Markdown under `# Registry search — category=<category>`. The category is passed to the registry as-is, so an unknown or misspelled category is **not** an error. It returns an empty listing (`*0 results*`). Take category names from `plungeai://agents/categories`. ```bash # verify # expect: category=financials # expect: sec-agent 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":11,"method":"resources/read","params":{"uri":"plungeai://agents/financials"}}' ``` ## Result shape `resources/read` answers one entry: ```json { "contents": [ { "uri": "plungeai://agents/{category}", "mimeType": "text/markdown", "text": "…" } ] } ``` ## Errors `resources/read` answers JSON-RPC errors, not outcomes; the SDK prefixes each message with `MCP error <code>:` ([resources/read](/mcp-reference/protocol/resources-read)). - `-32603` `Registry error <status>`: the registry answered with a non-2xx status. - `-32002` `Resource not found: <uri>`: the URI matches no resource or template. # Workflow YAML by id Source: https://docs-preview.plungeai.com/mcp-reference/resources/workflow-yaml `plungeai://workflows/{id}` · `text/yaml` · `template` The saved CNL YAML of one of **your** workflows, as `text/yaml`. The id is the workflow id from `plungeai_list_workflows` or `plungeai://workflows/list`. The ownership check comes first: an id that does not exist and an id owned by someone else get the same `-32002` answer, so you cannot probe for other accounts' ids. A workflow whose YAML body is missing from storage returns the text `No YAML content found`. ```bash # needs one of your workflow ids — not auto-verified 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":12,"method":"resources/read","params":{"uri":"plungeai://workflows/<workflow id>"}}' ``` ## Result shape `resources/read` answers one entry: ```json { "contents": [ { "uri": "plungeai://workflows/{id}", "mimeType": "text/yaml", "text": "…" } ] } ``` ## Errors `resources/read` answers JSON-RPC errors, not outcomes; the SDK prefixes each message with `MCP error <code>:` ([resources/read](/mcp-reference/protocol/resources-read)). - `-32002` `Workflow not found: <id>`: the workflow is unknown or not yours. - `-32002` `Resource not found: <uri>`: the URI matches no resource or template. # Execution result by id Source: https://docs-preview.plungeai.com/mcp-reference/resources/execution-result `plungeai://executions/{id}` · `text/markdown` · `template` The stored result of one of **your** runs, by **execution id** (not the workflow id, [Troubleshooting](https://mcp.plungeai.com/docs#15-troubleshooting--gotchas)). It reads the same stores as `plungeai_get_result`: the stored result, then the final task's output. The document looks like this: ``` # Execution <execution id> - **Workflow:** `<workflow id>` ## Result <the run's final output> ``` When there is no output, the Result section says why: | Run state | `## Result` text | |---|---| | failed | `_This run failed: <error message>._` (or `no error was recorded`) | | no output yet | `_No result stored yet (may still be running)._` | This resource gives the final result only. For one task's output, the full conversation thread, the "Steps in this run" index or a paused run's ⏸ block, use `plungeai_get_result` ([Runs, results & follow-ups](https://mcp.plungeai.com/docs#9-runs-results--follow-ups)). An unknown id, or one that is not yours, gets `-32002 Execution not found: <id>`. ```bash # needs one of your execution ids — not auto-verified 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":13,"method":"resources/read","params":{"uri":"plungeai://executions/<execution id>"}}' ``` ## Result shape `resources/read` answers one entry: ```json { "contents": [ { "uri": "plungeai://executions/{id}", "mimeType": "text/markdown", "text": "…" } ] } ``` ## Errors `resources/read` answers JSON-RPC errors, not outcomes; the SDK prefixes each message with `MCP error <code>:` ([resources/read](/mcp-reference/protocol/resources-read)). - `-32002` `Execution not found: <id>`: the execution is unknown or not yours. - `-32002` `Resource not found: <uri>`: the URI matches no resource or template. # plungeai Source: https://docs-preview.plungeai.com/mcp-reference/prompts/plungeai ## Arguments | Argument | Required | Description | |---|---|---| | `request` | no | What you want to accomplish (optional) | There is exactly one prompt. It activates the whole platform in one step. Earlier recipe prompts (research pipeline, market research, …) were removed on purpose: they showed up as separate slash commands and locked the client into one behaviour, when the tools already cover everything (`prompts.ts`). | Field | Value | |---|---| | `name` | `plungeai` | | `title` | `PlungeAI` | | `description` | `PlungeAI MCP` | | `arguments` | one: `request` (string, **optional**), "What you want to accomplish (optional)" | **Using it in a client.** Clients list MCP prompts in their slash-command or prompt menu. In Claude Code the prompt appears as `/plungeai:plungeai (MCP)`: type `/plungeai` to filter the menu and pick it, or run `/mcp__plungeai__plungeai` directly (the middle part is the server name you chose in `claude mcp add`). Claude Code splits any text after the command on whitespace, one word per argument, so only the first word would reach `request`. Run the prompt bare, then type your request as the next message. Other clients may offer a form field for `request` instead. - run bare (no `request`): the model is told to ask you what you want to accomplish; - with `request` set (for example `research Tesla's Q2`, from a client that offers the field): the model is told to handle that request now. The prompt is a convenience, not a requirement. You can always just talk to your client normally. `prompts/list`: ```bash # verify # expect: "name":"plungeai" # expect: "request" 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":"prompts/list"}' ``` `prompts/get` returns `description: "PlungeAI MCP"` and one `user` message (type `text`). It runs nothing, so it is free: ```bash # verify # expect: Now handle this request: research Tesla's Q2 # expect: plungeai_list_workflows 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":2,"method":"prompts/get","params":{"name":"plungeai","arguments":{"request":"research Tesla'"'"'s Q2"}}}' ``` What the message tells the model: - It now has the full platform through the `plungeai_*` tools: about 90 active agents, CNL workflows, missions, long-term memory and execution history. - **Discover.** "Show me my agents/workflows" means saved workflows (`plungeai_list_workflows`). The registry (`plungeai_list_agents` with a natural-language `search`) is for building blocks. Fetch a full card with `agent_id` before first use. - **Execute.** `plungeai_execute_agent` (one agent, optional `session_id`), `plungeai_execute_workflow` (saved `workflow_id` or ad-hoc CNL YAML), `plungeai_run_mission` (bounded autonomous loop with memory). - **Results.** `plungeai_get_result`, `plungeai_get_workflow_status` (poll async runs), `plungeai_executions`, and `plungeai_followup` / `plungeai_continue` for finished or paused runs. - **Approvals.** Relay any "⏸ AWAITING USER APPROVAL" or "⏸ AWAITING USER" block verbatim, never approve on its own, then call `plungeai_continue` with `approve: true` or the user's words. - **Build.** `plungeai_build_workflow` generates and saves a workflow. `plungeai_workflow` is direct CRUD. `plungeai_memory` is long-term memory. - Always pass `user_request`, the user's words verbatim. - The last line is either `Now handle this request: <request>` (the argument is trimmed) or `Ask the user what they want to accomplish.` when `request` is empty or absent. An unknown prompt name is **rejected** with `-32602`. The SDK prefixes the message with `MCP error -32602:`: ```bash # verify # expect: "code":-32602 # expect: Prompt not found: research 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":3,"method":"prompts/get","params":{"name":"research"}}' ``` ## Returned message `prompts/get` returns one `user` message with this text (`orchestration/mcp-gateway/prompts.ts`): ```text "Returned message" [expandable] You now have the full PlungeAI platform available through the plungeai_* tools: ~90 active agents (search, financial, documents, social, payments, automation, …), CNL YAML workflows, autonomous missions, long-term memory, and execution history. How to work with it: - **Discover**: "show me my agents/workflows" means the user's SAVED WORKFLOWS → plungeai_list_workflows. The registry (plungeai_list_agents, search:"<capability in natural language>" — hybrid semantic search, trust the ranking; fetch a full card with agent_id before first use) is the capability catalog of building-block agents — use it when the user says registry/discovery, or when composing workflows. - **Execute**: plungeai_execute_agent (one agent, optional session_id for conversations), plungeai_execute_workflow (saved workflow_id or ad-hoc CNL YAML — sequential, parallel, dynamic, batch), plungeai_run_mission (bounded autonomous loop with memory). - **Results**: plungeai_get_result and plungeai_get_workflow_status (poll async runs); plungeai_executions for history; plungeai_followup / plungeai_continue to keep talking to a finished or paused run. - **Approvals (HITL)**: if a result or status ends with "⏸ AWAITING USER APPROVAL" or "⏸ AWAITING USER", relay it to the user verbatim and ask them to decide (e.g. "Approve? yes/no") — never approve on your own — then plungeai_continue with the execution_id and approve: true or message: "<their words>". - **Build**: plungeai_build_workflow generates and saves a workflow from a goal; plungeai_workflow is direct CRUD. plungeai_memory for long-term memory. - Always pass user_request (the user's words, verbatim) on every call. Ask the user what they want to accomplish. ``` With `request` set, the last line reads `Now handle this request: <request>` instead. # initialize Source: https://docs-preview.plungeai.com/mcp-reference/protocol/initialize Opens a conversation: the server answers with the negotiated protocol version, its identity, its capabilities and the `instructions` text your client adds to the model's context. Support: **supported**. Each request stands alone, so `tools/list` and `tools/call` also work without a prior `initialize`. ## Params | Param | Type | Required | Description | |---|---|---|---| | `protocolVersion` | string | yes | The revision your client speaks. `2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05` and `2024-10-07` are answered with that version; anything else gets `2025-11-25` | | `capabilities` | object | yes | Your client capabilities; `{}` is fine | | `clientInfo` | object | yes | `{ "name", "version" }` of your client | ## Result | Field | Value | |---|---| | `protocolVersion` | The negotiated version | | `serverInfo` | `{ "name": "plungeai.com", "version": "2.5.1" }`; the version moves with deploys | | `capabilities` | `logging: {}`, `resources: {}`, `prompts: {}`, `tools: { listChanged: true }`; the stateless server never sends `list_changed` | | `instructions` | The server-level usage guide for the model | ## Example ```bash Request 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":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}' ``` ```json Response {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-11-25","capabilities":{"logging":{},"resources":{},"prompts":{},"tools":{"listChanged":true}},"serverInfo":{"name":"plungeai.com","version":"2.5.1"},"instructions":"…"}} ``` The response above is abridged: the long `instructions` string is shortened to `…`. ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 200 | `-32602` | `Invalid params: <fields>` for malformed params, for example a numeric `protocolVersion` and no `clientInfo` | | 400 | `-32600` | A batch that holds `initialize` together with other messages | | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). ## notifications/initialized After `initialize` your client sends `notifications/initialized`. It has no `id`, so the server answers `202 Accepted` with an empty body. ```bash curl -s -o /dev/null -w '%{http_code}\n' 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","method":"notifications/initialized"}' ``` # tools/list Source: https://docs-preview.plungeai.com/mcp-reference/protocol/tools-list Returns the 20 `plungeai_*` tools in catalog order, or only the tools your key is fenced to. Support: **supported**; there is no pagination, so no `nextCursor` comes back and a `cursor` param is ignored. ## Params | Param | Type | Required | Description | |---|---|---|---| | `cursor` | string | no | Ignored: the full list comes back every time | ## Result | Field | Value | |---|---| | `tools[]` | One entry per tool: `name`, `description` and `inputSchema` (JSON Schema) | | `tools[].annotations` | `{ "readOnlyHint": true }` on the six read-only tools; the other 14 carry no annotations | | `tools[].outputSchema` | On seven tools: the outcome envelope on six, the status object on `plungeai_get_workflow_status` | ## Example ```bash Request 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":2,"method":"tools/list"}' ``` ```json Response {"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"plungeai_whoami","description":"…","inputSchema":{"type":"object","properties":{"user_request":{"type":"string"},"format":{"type":"string","enum":["markdown","json"]}}},"annotations":{"readOnlyHint":true}}]}} ``` The response above is abridged to one of the 20 entries, and its `description` string is shortened to `…`. The exact schemas are in [/mcp-tools.json](/mcp-tools.json) and on each [tool page](/mcp-reference/tools/plungeai_whoami). ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). # tools/call Source: https://docs-preview.plungeai.com/mcp-reference/protocol/tools-call Runs one tool. Support: **supported**. The answer is a server-sent-event stream: each frame is `event: message` plus one `data:` line, progress notifications come first, and the last frame is the JSON-RPC response. ## Params | Param | Type | Required | Description | |---|---|---|---| | `name` | string | yes | The tool name, for example `plungeai_whoami` | | `arguments` | object | yes | The tool's arguments; always include `user_request`, the user's own words | | `_meta.progressToken` | string or number | no | When set, progress arrives as `notifications/progress`; without it, as `notifications/message` at level `info` | ## Result | Field | Value | |---|---| | `content[]` | `[{ "type": "text", "text": "…" }]`: Markdown by default, JSON text with `format: "json"` | | `structuredContent` | The same answer as an object on tools with an output schema, or with `format: "json"` | | `isError` | `true` only for an `error` outcome | ## Example ```bash Request 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":3,"method":"tools/call","params":{"name":"plungeai_whoami","arguments":{"user_request":"who am I"}}}' ``` ```text Response event: message data: {"result":{"content":[{"type":"text","text":"# Who am I\n…"}]},"jsonrpc":"2.0","id":3} ``` The response above is abridged: the tool's Markdown text is shortened to `…`. Four tools accept `mode: "async"` and answer at once with an execution id; poll `plungeai_get_workflow_status`, then read the output with `plungeai_get_result`. A pre-screen answer (unknown or fenced tool, bad arguments) and every edge error come back as plain JSON, so check `Content-Type` before parsing. ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 200 | `-32602` | `Tool not found: <name>`, or `Tool not permitted for this key: <name>` for a fenced key | | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | | 429 | `-32000` | Rate limit reached (counted on `tools/call` only); `Retry-After` and `error.data.retryAfter` give the seconds | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). # resources/list Source: https://docs-preview.plungeai.com/mcp-reference/protocol/resources-list Returns the five fixed `plungeai://` resources. Support: **supported**. ## Params None: send `"params": {}` or leave `params` out. ## Result | Field | Value | |---|---| | `resources[].uri` | `plungeai://agents/list`, `plungeai://agents/categories`, `plungeai://personas/list`, `plungeai://workflows/list`, `plungeai://docs/workflow-authoring` | | `resources[].name` | PlungeAI Agents, Agent Categories, Personas, Your Workflows, Workflow Authoring Guide | | `resources[].mimeType` | `text/markdown` for all five | ## Example ```bash Request 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":4,"method":"resources/list"}' ``` ```json Response {"jsonrpc":"2.0","id":4,"result":{"resources":[{"uri":"plungeai://agents/list","name":"PlungeAI Agents","description":"Live agent registry (markdown)","mimeType":"text/markdown"}]}} ``` The response above is abridged to one of the five entries; every resource has its own page under [Resources](/mcp-reference/resources/agents-list). ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). # resources/templates/list Source: https://docs-preview.plungeai.com/mcp-reference/protocol/resources-templates-list Returns the three URI templates for resources addressed by a parameter. Support: **supported**. ## Params None: send `"params": {}` or leave `params` out. ## Result | Field | Value | |---|---| | `resourceTemplates[].uriTemplate` | `plungeai://agents/{category}`, `plungeai://workflows/{id}`, `plungeai://executions/{id}` | | `resourceTemplates[].name` | Agents by category, Workflow YAML by id, Execution result by id | | `resourceTemplates[].mimeType` | `text/markdown`, `text/yaml`, `text/markdown` | ## Example ```bash Request 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":5,"method":"resources/templates/list"}' ``` ```json Response {"jsonrpc":"2.0","id":5,"result":{"resourceTemplates":[{"uriTemplate":"plungeai://agents/{category}","name":"Agents by category","mimeType":"text/markdown"},{"uriTemplate":"plungeai://workflows/{id}","name":"Workflow YAML by id","mimeType":"text/yaml"},{"uriTemplate":"plungeai://executions/{id}","name":"Execution result by id","mimeType":"text/markdown"}]}} ``` ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). # resources/read Source: https://docs-preview.plungeai.com/mcp-reference/protocol/resources-read Reads one resource or template instance. Support: **supported**. ## Params | Param | Type | Required | Description | |---|---|---|---| | `uri` | string | yes | A static URI or a filled-in template, for example `plungeai://agents/categories` | ## Result | Field | Value | |---|---| | `contents[]` | One entry: `{ "uri", "mimeType", "text" }` | ## Example ```bash Request 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":6,"method":"resources/read","params":{"uri":"plungeai://agents/categories"}}' ``` ```json Response {"jsonrpc":"2.0","id":6,"result":{"contents":[{"uri":"plungeai://agents/categories","mimeType":"text/markdown","text":"…"}]}} ``` The response above is abridged: the resource's Markdown `text` is shortened to `…`. ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 200 | `-32002` | `MCP error -32002: Resource not found: <uri>`; also `Workflow not found` and `Execution not found` for the two id templates | | 200 | `-32603` | `Registry error <status>` when the registry behind an agent, category or persona resource fails, or a missing `uri` | | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). # prompts/list Source: https://docs-preview.plungeai.com/mcp-reference/protocol/prompts-list Returns the one prompt, `plungeai`. Support: **supported**. In Claude Code it appears as `/plungeai:plungeai (MCP)`. ## Params None: send `"params": {}` or leave `params` out. ## Result | Field | Value | |---|---| | `prompts[].name` | `plungeai` | | `prompts[].title` | `PlungeAI` | | `prompts[].description` | `PlungeAI MCP` | | `prompts[].arguments` | One: `request` (optional), "What you want to accomplish (optional)" | ## Example ```bash Request 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":7,"method":"prompts/list"}' ``` ```json Response {"jsonrpc":"2.0","id":7,"result":{"prompts":[{"name":"plungeai","title":"PlungeAI","description":"PlungeAI MCP","arguments":[{"name":"request","description":"What you want to accomplish (optional)","required":false}]}]}} ``` ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). # prompts/get Source: https://docs-preview.plungeai.com/mcp-reference/protocol/prompts-get Returns the prompt's message. Support: **supported**. It runs nothing, so it is free. ## Params | Param | Type | Required | Description | |---|---|---|---| | `name` | string | yes | `plungeai` | | `arguments.request` | string | no | What the user wants; without it the message tells the model to ask | ## Result | Field | Value | |---|---| | `description` | `PlungeAI MCP` | | `messages[]` | One `user` message of type `text`, ending with `Now handle this request: <request>` or `Ask the user what they want to accomplish.` | ## Example ```bash Request 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":8,"method":"prompts/get","params":{"name":"plungeai","arguments":{"request":"summarise my last run"}}}' ``` ```json Response {"jsonrpc":"2.0","id":8,"result":{"description":"PlungeAI MCP","messages":[{"role":"user","content":{"type":"text","text":"…Now handle this request: summarise my last run"}}]}} ``` The response above is abridged: the start of the prompt text is shortened to `…`; only its last sentence is shown. ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 200 | `-32602` | `MCP error -32602: Prompt not found: <name>` | | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). # ping Source: https://docs-preview.plungeai.com/mcp-reference/protocol/ping A liveness check. Support: **supported**. ## Params None: send `"params": {}` or leave `params` out. ## Result | Field | Value | |---|---| | `result` | `{}` | ## Example ```bash Request 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":9,"method":"ping"}' ``` ```json Response {"jsonrpc":"2.0","id":9,"result":{}} ``` ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). # logging/setLevel Source: https://docs-preview.plungeai.com/mcp-reference/protocol/logging-set-level Support: **partial**. The server answers `{}`, but each request gets a fresh server instance, so the level is not applied to later calls. Progress fallback lines are always sent at level `info`. ## Params | Param | Type | Required | Description | |---|---|---|---| | `level` | string | yes | An MCP logging level, for example `info` | ## Result | Field | Value | |---|---| | `result` | `{}` | ## Example ```bash Request 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":10,"method":"logging/setLevel","params":{"level":"info"}}' ``` ```json Response {"jsonrpc":"2.0","id":10,"result":{}} ``` ## Errors Protocol errors mean the request never reached a tool; the body is `{"jsonrpc":"2.0","error":{"code":…,"message":"…"},"id":…}`. | HTTP | Code | When | |---|---|---| | 401 | `-32001` | No key, or a wrong, revoked or expired key, or a bearer that does not start with `ozk_` | The full table is on the [MCP Reference overview](/mcp-reference/overview#errors). # Get balance Source: https://docs-preview.plungeai.com/account-api/balance/get-balance <Info> Planned: not available yet. Tracked as TI-02. </Info> Dashboard view, not an API. ## What this will do A key-authenticated route will return the wallet balance. Today **Dashboard → One API → Billing** shows the wallet balance, lifetime top-ups and spend, the auto-recharge setting, the account status and trial allowance, and the saved card (brand and last four digits). ## Use this today <Card title="Open the Billing tab" icon="credit-card" href="https://dashboard.plungeai.com/one-api?tab=billing"> Top up the wallet and see spend in Dashboard → One API → Billing. </Card> <!-- placeholder-source: content/_placeholders.json --> # Add to balance Source: https://docs-preview.plungeai.com/account-api/balance/add-to-balance <Info> Planned: not available yet. Tracked as TI-02. </Info> Dashboard view, not an API. ## What this will do A key-authenticated route will add funds to the wallet. Today a top-up in **Dashboard → One API → Billing** opens a Stripe Checkout page; amounts run from 5 to 10,000 USD. ## Use this today <Card title="Open the Billing tab" icon="credit-card" href="https://dashboard.plungeai.com/one-api?tab=billing"> Top up the wallet and see spend in Dashboard → One API → Billing. </Card> <!-- placeholder-source: content/_placeholders.json --> # Create key Source: https://docs-preview.plungeai.com/account-api/keys/create-key <Info> Planned: not available yet. Tracked as TI-01. </Info> Dashboard view, not an API. ## What this will do In **Dashboard → One API → Keys** you name a key (1 to 64 characters), pick an expiry (never, 7, 30, 90, 180 or 365 days) and copy the secret, which is shown once. At most 25 keys can be active. A new key takes the account's tier. Model keys (`sk-ocean-`) and connector keys (`sk-conn-`) are created in the Dashboard too; Authentication says which key each plane takes. ## Use this today <CardGroup cols={2}> <Card title="Open the Keys tab" icon="key" href="https://dashboard.plungeai.com/one-api?tab=keys"> Create and revoke keys in the Dashboard. </Card> <Card title="Authentication" icon="shield" href="/getting-started/authentication"> The three key prefixes and which routes accept which key. </Card> </CardGroup> <!-- placeholder-source: content/_placeholders.json --> # Delete key Source: https://docs-preview.plungeai.com/account-api/keys/delete-key <Info> Planned: not available yet. Tracked as TI-01. </Info> Dashboard view, not an API. ## What this will do A key-authenticated route will revoke a key. Today you revoke a key in **Dashboard → One API → Keys**; revocation takes effect within about a minute. ## Use this today <Card title="Open the Keys tab" icon="key" href="https://dashboard.plungeai.com/one-api?tab=keys"> Create and revoke keys in the Dashboard. </Card> <!-- placeholder-source: content/_placeholders.json --> # Get usage Source: https://docs-preview.plungeai.com/account-api/usage/get-usage <Info> Planned: not available yet. Tracked as TI-03. </Info> Dashboard view, not an API. ## What this will do A key-authenticated route will return usage and cost. Today **Dashboard → One API → Requests** and **Billing** show runs, tokens and cost, grouped by user, workflow, model or channel, over 7, 30 or 90 days, for you and your connected users. Per-run cost is in traces. ## Use this today <CardGroup cols={2}> <Card title="Open the Billing tab" icon="credit-card" href="https://dashboard.plungeai.com/one-api?tab=billing"> Top up the wallet and see spend in Dashboard → One API → Billing. </Card> <Card title="History & Cost" icon="chart" href="/traces/history-and-cost"> Read per-run cost from traces. </Card> </CardGroup> <!-- placeholder-source: content/_placeholders.json --> # Who am I Source: https://docs-preview.plungeai.com/account-api/identity/whoami <Note> Available now over MCP; a REST route is tracked as TI-79. </Note> Read the identity behind your key: the user, the auth type and tier, the key label and id, and the current rate-limit window. It is the `plungeai_whoami` tool of the MCP server, so any MCP client can call it, and it is read-only. <!-- Handler: orchestration/mcp-gateway/extras.ts:692-737 (WhoamiSchema and plungeaiWhoami: the Markdown text at :725, the JSON fields at :728-735; tier, key_label and key_id are null when absent). --> ## Endpoint ```text POST https://mcp.plungeai.com/v1 · tools/call · name: plungeai_whoami ``` ## Authorizations `Authorization: Bearer $PLUNGE_API_KEY` or `X-API-Key: $PLUNGE_API_KEY`, an `ozk_` key from **Dashboard → One API → Keys**. The call counts toward your rate limit, so the window it reports includes it. ## Arguments <ParamField body="user_request" type="string"> The user's words, up to 4,000 characters. Optional. </ParamField> <ParamField body="format" type="string" default="markdown"> `markdown` or `json`. `json` returns the fields below as a JSON document and as `structuredContent`. </ParamField> ## Output With `format: "markdown"` (the default) the text starts with `# Who am I` and lists User, Auth (type and tier), Key (label and key id), Rate window (`<n>/min used · <n>/day used`, left out when the counter cannot be read) and Server. With `format: "json"`: <ResponseField name="user" type="string"> Your user id. </ResponseField> <ResponseField name="auth_type" type="string"> How the request authenticated, `api-key` for an `ozk_` key. </ResponseField> <ResponseField name="tier" type="string | null"> The key's tier: `free`, `pro` or `enterprise`, or `null` when the key carries none. </ResponseField> <ResponseField name="key_label" type="string | null"> The name you gave the key in the Dashboard, or `null` when it has none. </ResponseField> <ResponseField name="key_id" type="string | null"> The key's id, or `null` when it is not known. </ResponseField> <ResponseField name="rate_window" type="object | null"> `{ "minute_used", "day_used" }` for the current windows, or `null` when the counter cannot be read. </ResponseField> <ResponseField name="server" type="string"> The server name and host, `plungeai.com (mcp.plungeai.com)`. </ResponseField> ## Example ```python Python import json, os, requests r = requests.post( "https://mcp.plungeai.com/v1", headers={ "Authorization": f"Bearer {os.environ['PLUNGE_API_KEY']}", "Content-Type": "application/json", "Accept": "application/json, text/event-stream", }, json={"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "plungeai_whoami", "arguments": {"user_request": "who am I?", "format": "json"}}}, ) frames = [line[len("data: "):] for line in r.text.splitlines() if line.startswith("data: ")] print(json.loads(frames[-1])["result"]["structuredContent"]) ``` ```typescript TypeScript import { Client } from '@modelcontextprotocol/sdk/client/index.js' import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js' const transport = new StreamableHTTPClientTransport(new URL('https://mcp.plungeai.com/v1'), { requestInit: { headers: { Authorization: `Bearer ${process.env.PLUNGE_API_KEY}` } }, }) const client = new Client({ name: 'whoami-example', version: '1.0.0' }) await client.connect(transport) const result = await client.callTool({ name: 'plungeai_whoami', arguments: { user_request: 'who am I?' } }) console.log(result.content) ``` ```bash cURL 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_whoami","arguments":{"user_request":"who am I?"}}}' ``` Result shape, Markdown form (the field layout of the tool reference; every value is a placeholder): ```markdown # Who am I - **User:** `00000000-0000-4000-8000-000000000005` - **Auth:** api-key · tier **free** - **Key:** my-laptop (`00000000-0000-4000-8000-000000000008`) - **Rate window:** 1/min used · 12/day used - **Server:** plungeai.com (mcp.plungeai.com) ``` Result shape, JSON form (`format: "json"`, the `structuredContent`; every value is a placeholder): ```json { "user": "00000000-0000-4000-8000-000000000005", "auth_type": "api-key", "tier": "free", "key_label": "my-laptop", "key_id": "00000000-0000-4000-8000-000000000008", "rate_window": { "minute_used": 1, "day_used": 12 }, "server": "plungeai.com (mcp.plungeai.com)" } ``` The same tool is documented field by field on [plungeai_whoami](/mcp-reference/tools/plungeai_whoami). # Agent Skills Source: https://docs-preview.plungeai.com/skills ## Install [Download all skills (zip)](https://skills.plungeai.com/plungeai-agent-skills.zip) The public repository is publishing soon — until then, download a zip from any skill below. ## Browse All (31) · [Start here (4)](#start-here) · [Capability (12)](#capability) · [In your tool (12)](#in-your-tool) · [Studio kinds (3)](#studio-kinds) ## Start here <CardGroup cols={2}> <Card title="choose-your-plungeai-door" icon="sparkles"> Picks the right PlungeAI entry point before you write anything — the MCP server (https://mcp.plungeai.com/v1) for live agent operation, the One API (https://api.plungeai.com) for code you write or… [View skill](/skills/choose-your-plungeai-door) · [Download zip](https://skills.plungeai.com/choose-your-plungeai-door.zip) </Card> <Card title="plungeai-api-setup" icon="sparkles"> Setup for the PlungeAI One API (https://api.plungeai.com) — a self-service ozk_ key, the base URL, the Bearer/X-API-Key auth header, your first curl call, the live OpenAPI 3.1 contract at… [View skill](/skills/plungeai-api-setup) · [Download zip](https://skills.plungeai.com/plungeai-api-setup.zip) </Card> <Card title="plungeai-cli-setup" icon="sparkles"> Operate the Ocean CLI (`ocean`; package @plungeai/ocean-cli — not yet on npm, run from the Ocean-Platform repo) to drive PlungeAI from a terminal: install/setup, auth (Studio session cookie vs… [View skill](/skills/plungeai-cli-setup) · [Download zip](https://skills.plungeai.com/plungeai-cli-setup.zip) </Card> <Card title="plungeai-mcp-setup" icon="sparkles"> Connect and operate the PlungeAI MCP server (https://mcp.plungeai.com/v1) — endpoint and Bearer ozk_/X-API-Key auth, a generic MCP client config (native remote/HTTP, or the mcp-remote stdio bridge)… [View skill](/skills/plungeai-mcp-setup) · [Download zip](https://skills.plungeai.com/plungeai-mcp-setup.zip) </Card> </CardGroup> ## Capability <CardGroup cols={2}> <Card title="plungeai-agents" icon="sparkles"> Run a PlungeAI registry agent: recognize the two kinds (prompt-driven vs structured tool-agents), execute a prompt-driven one sync or async (`plungeai_execute_agent` MCP / `POST… [View skill](/skills/plungeai-agents) · [Download zip](https://skills.plungeai.com/plungeai-agents.zip) </Card> <Card title="plungeai-campaigns" icon="sparkles"> Run a list to completion on PlungeAI: the campaign ledger (claim/complete/fail/retry over data-table-agent), the campaign-config block (list source, cycle, cadence, retries, delivery), and how a… [View skill](/skills/plungeai-campaigns) · [Download zip](https://skills.plungeai.com/plungeai-campaigns.zip) </Card> <Card title="plungeai-discovery" icon="sparkles"> Find the right thing on PlungeAI's live registry before building anything: agents, structured tools, models, skills, personas, connectors, and saved workflow templates, via hybrid semantic + keyword… [View skill](/skills/plungeai-discovery) · [Download zip](https://skills.plungeai.com/plungeai-discovery.zip) </Card> <Card title="plungeai-memory" icon="sparkles"> Read and write PlungeAI's per-user long-term memory (plungeai_memory: recall/remember/search_runs/get_run) and distill a session into a reusable skill with plungeai_learn — distinct from… [View skill](/skills/plungeai-memory) · [Download zip](https://skills.plungeai.com/plungeai-memory.zip) </Card> <Card title="plungeai-missions" icon="sparkles"> Run bounded autonomous PlungeAI agent missions (type: harness) — a goal, a tool fence, an iteration cap, and self-checked success criteria, via plungeai_run_mission or a harness workflow task. [View skill](/skills/plungeai-missions) · [Download zip](https://skills.plungeai.com/plungeai-missions.zip) </Card> <Card title="plungeai-models" icon="sparkles"> Model routing on PlungeAI: how agents/workflows/missions resolve a model through the platform's provider factory (`model`/`provider` fields on a task or mission), and the separate OpenAI-compatible… [View skill](/skills/plungeai-models) · [Download zip](https://skills.plungeai.com/plungeai-models.zip) </Card> <Card title="plungeai-platform" icon="sparkles"> THE PlungeAI (Ocean) platform capability map: a growing live registry of agents and structured tools, CNL multi-agent workflows, bounded harness missions, injectable skills/plugins/experts/personas… [View skill](/skills/plungeai-platform) · [Download zip](https://skills.plungeai.com/plungeai-platform.zip) </Card> <Card title="plungeai-results-traces" icon="sparkles"> Debug and observe PlungeAI runs: live SSE events, plungeai_get_workflow_status / plungeai_executions history, persisted GET /v1/traces/{id} spans and gateway request cost, the HITL conversation loop… [View skill](/skills/plungeai-results-traces) · [Download zip](https://skills.plungeai.com/plungeai-results-traces.zip) </Card> <Card title="plungeai-scheduling" icon="sparkles"> Cron-schedule PlungeAI workflows, agent queries, pre-built agent cards, and condition-watching heartbeats via plungeai_schedule, with full run history and retries. [View skill](/skills/plungeai-scheduling) · [Download zip](https://skills.plungeai.com/plungeai-scheduling.zip) </Card> <Card title="plungeai-skills-plugins" icon="sparkles"> Declare and understand PlungeAI's capability-injection fields on a type: harness task or plungeai_run_mission — skills, experts, persona, backgrounds, plugins, and MCP servers — including… [View skill](/skills/plungeai-skills-plugins) · [Download zip](https://skills.plungeai.com/plungeai-skills-plugins.zip) </Card> <Card title="plungeai-tools-connectors" icon="sparkles"> Call PlungeAI structured tool-agents with typed parameters against a published invocation contract: fetch the contract (`plungeai_get_tool_contract` / `GET /v1/tools/{id}`), execute with typed… [View skill](/skills/plungeai-tools-connectors) · [Download zip](https://skills.plungeai.com/plungeai-tools-connectors.zip) </Card> <Card title="plungeai-workflows" icon="sparkles"> Build, validate, test, and save PlungeAI (Ocean Studio) workflows in CNL YAML. [View skill](/skills/plungeai-workflows) · [Download zip](https://skills.plungeai.com/plungeai-workflows.zip) </Card> </CardGroup> ## In your tool <CardGroup cols={2}> <Card title="plungeai-in-bolt" icon="sparkles"> Connect Bolt.new to PlungeAI (Ocean Studio) over MCP — the Connectors → Custom MCP server form, the all-tools/all-projects toggle behavior, keeping the shipped app's key server-side, and a… [View skill](/skills/plungeai-in-bolt) · [Download zip](https://skills.plungeai.com/plungeai-in-bolt.zip) </Card> <Card title="plungeai-in-claude-ai" icon="sparkles"> Connect claude.ai web or Claude Desktop to PlungeAI (Ocean Studio) — Desktop live tools via the mcp-remote bridge in claude_desktop_config.json (OAuth isn't available yet, hence the bridge)… [View skill](/skills/plungeai-in-claude-ai) · [Download zip](https://skills.plungeai.com/plungeai-in-claude-ai.zip) </Card> <Card title="plungeai-in-claude-code" icon="sparkles"> Connect the Claude Code CLI to PlungeAI (Ocean Studio) over MCP — 'claude mcp add' one-liner, project-scoped .mcp.json with an env-var key, the skills/plugin install path, and a plungeai_whoami +… [View skill](/skills/plungeai-in-claude-code) · [Download zip](https://skills.plungeai.com/plungeai-in-claude-code.zip) </Card> <Card title="plungeai-in-codex" icon="sparkles"> Connect OpenAI Codex CLI to PlungeAI (Ocean Studio) over MCP — native streamable-HTTP in ~/.codex/config.toml (env-var or static bearer token), the codex mcp add terminal command, the mcp-remote… [View skill](/skills/plungeai-in-codex) · [Download zip](https://skills.plungeai.com/plungeai-in-codex.zip) </Card> <Card title="plungeai-in-cursor" icon="sparkles"> Connect Cursor to PlungeAI (Ocean Studio) over MCP — the one-click install-page deeplink or a ~/.cursor/mcp.json entry, Agent/Plan-mode tool behavior, the ~40-tool cap, and a plungeai_whoami +… [View skill](/skills/plungeai-in-cursor) · [Download zip](https://skills.plungeai.com/plungeai-in-cursor.zip) </Card> <Card title="plungeai-in-gemini-cli" icon="sparkles"> Connect Gemini CLI to PlungeAI (Ocean Studio) over MCP — a ~/.gemini/settings.json entry using httpUrl (not url, which is SSE-only and 405s), the mcp-remote bridge fallback, /mcp reload after edits… [View skill](/skills/plungeai-in-gemini-cli) · [Download zip](https://skills.plungeai.com/plungeai-in-gemini-cli.zip) </Card> <Card title="plungeai-in-lovable" icon="sparkles"> Connect Lovable to PlungeAI (Ocean Studio) — a personal chat connector (any plan) so Lovable's chat can operate PlungeAI via MCP while building, and a workspace-admin app connector so shipped apps… [View skill](/skills/plungeai-in-lovable) · [Download zip](https://skills.plungeai.com/plungeai-in-lovable.zip) </Card> <Card title="plungeai-in-opencode" icon="sparkles"> Connect OpenCode to PlungeAI (Ocean Studio) over MCP — an opencode.json mcp.plungeai entry with type: remote, {env:VAR} variable substitution for a committed project config, and a plungeai_whoami +… [View skill](/skills/plungeai-in-opencode) · [Download zip](https://skills.plungeai.com/plungeai-in-opencode.zip) </Card> <Card title="plungeai-in-replit" icon="sparkles"> Connect Replit Agent to PlungeAI (Ocean Studio) over MCP — the one-click install-page link, the Integrations → MCP Servers form, keeping the Agent's MCP key separate from a deployed app's Replit… [View skill](/skills/plungeai-in-replit) · [Download zip](https://skills.plungeai.com/plungeai-in-replit.zip) </Card> <Card title="plungeai-in-v0" icon="sparkles"> Connect v0 (Vercel) to PlungeAI (Ocean Studio) over MCP — the + menu → MCPs form, why the generated Next.js app must call PlungeAI through a server Route Handler (v0 apps can't call MCP directly)… [View skill](/skills/plungeai-in-v0) · [Download zip](https://skills.plungeai.com/plungeai-in-v0.zip) </Card> <Card title="plungeai-in-vscode" icon="sparkles"> Connect VS Code (GitHub Copilot agent mode) to PlungeAI (Ocean Studio) over MCP — the code --add-mcp CLI command, a committed-safe .vscode/mcp.json with an input-prompted key, the… [View skill](/skills/plungeai-in-vscode) · [Download zip](https://skills.plungeai.com/plungeai-in-vscode.zip) </Card> <Card title="plungeai-in-windsurf" icon="sparkles"> Connect Windsurf (Cascade) to PlungeAI (Ocean Studio) over MCP — a ~/.codeium/windsurf/mcp_config.json entry using serverUrl, the mcp-remote bridge fallback for stdio-only builds, the 100-tool cap… [View skill](/skills/plungeai-in-windsurf) · [Download zip](https://skills.plungeai.com/plungeai-in-windsurf.zip) </Card> </CardGroup> ## Studio kinds <CardGroup cols={2}> <Card title="plungeai-agentic-agent" icon="sparkles"> Design and emit ONE bounded agentic agent for PlungeAI (Ocean Studio) as a single `type: harness` mission — purpose, allowed_tools fence, permissions gates (deny/ask), skills/plugins/MCP/persona… [View skill](/skills/plungeai-agentic-agent) · [Download zip](https://skills.plungeai.com/plungeai-agentic-agent.zip) </Card> <Card title="plungeai-bot-agent" icon="sparkles"> Design and emit ONE PlungeAI (Ocean Studio) bot agent — a scheduled, unattended `type: harness` mission that reports to the user's channels (in-app, email, Slack, Telegram, WhatsApp, Discord) — as… [View skill](/skills/plungeai-bot-agent) · [Download zip](https://skills.plungeai.com/plungeai-bot-agent.zip) </Card> <Card title="plungeai-campaign-agent" icon="sparkles"> Design and emit ONE PlungeAI (Ocean Studio) campaign agent — a long-running, list-driven, resumable agent that works an owned ledger of items in short scheduled runs until the current cycle is… [View skill](/skills/plungeai-campaign-agent) · [Download zip](https://skills.plungeai.com/plungeai-campaign-agent.zip) </Card> </CardGroup> # choose-your-plungeai-door Source: https://docs-preview.plungeai.com/skills/choose-your-plungeai-door Picks the right PlungeAI entry point before you write anything — the MCP server (https://mcp.plungeai.com/v1) for live agent operation, the One API (https://api.plungeai.com) for code you write or generate, the Ocean CLI for a terminal or CI workflow, or Ocean Studio for a human building visually — and names the setup or capability skill to load next. Use when the user asks which PlungeAI door, API, or interface to use, says "how do I use PlungeAI", "what's the difference between the MCP server and the One API", asks "does PlungeAI have a CLI/SDK/UI", or is choosing between MCP, REST, CLI, and Studio before writing any code. For the mechanics once a door is picked, use `plungeai-mcp-setup` (MCP), `plungeai-api-setup` (REST/codegen), or `plungeai-cli-setup` (terminal); for wiring a specific coding tool's agent to PlungeAI use `plungeai-in-<tool>`; the full capability map lives in `plungeai-platform`. [Download zip](https://skills.plungeai.com/choose-your-plungeai-door.zip) · [View raw SKILL.md](https://skills.plungeai.com/choose-your-plungeai-door/SKILL.md) PlungeAI (internally "Ocean") is a Cloudflare-native agent runtime: every agent, tool, and workflow runs as a deployed edge service. There is no local mode — everything you execute runs on the deployed platform, and everything you read (catalogs, contracts, results) is live. You reach it through one of four doors, all backed by the same identity and the same data (a workflow saved through one door appears in every other door and in Studio). ## The four doors | Door | What it is | Use it when | |---|---|---| | **MCP server** — `https://mcp.plungeai.com/v1` | The `plungeai_*` tool suite over MCP (Streamable HTTP) | You are an AI agent operating the platform live in a chat/agent context: discover, execute, save, schedule, remember. The richest surface — structured outcomes, approvals, continuations. | | **One API** — `https://api.plungeai.com` | REST gateway, OpenAPI 3.1 at `GET /v1/openapi.json` | You are writing or GENERATING code that calls PlungeAI: apps, scripts, backends, CI jobs, SDK wrappers. | | **Ocean CLI** — `ocean` | Terminal client (not yet on npm — install from the Ocean-Platform repo, or your administrator's build) | A human (or a script) works from a shell or CI pipeline: auth, doctor, running saved flows, scheduling. | | **Ocean Studio** | Browser app at `https://studio.plungeai.com` | A human builds/edits workflows visually, reviews runs, connects OAuth credentials, configures schedules — anything a door refuses (credential connect, OAuth, visual editing). | ## Rules of thumb - **Operating live from a chat/agent context → MCP.** One tool call per intent; the platform renders final user-ready markdown — relay it verbatim. Setup: `plungeai-mcp-setup`. Full guide: https://mcp.plungeai.com/docs#0-overview - **Generating code for a user's project → One API.** Point codegen at `GET /v1/openapi.json`; never invent routes. Setup: `plungeai-api-setup`. - **A human or CI script driving a terminal → Ocean CLI.** Setup: `plungeai-cli-setup`. - **Anything a door refuses (credential connect, OAuth, visual editing) → send the user to Ocean Studio.** No skill needed — it's a browser app. - **Connecting a *specific* coding tool's agent** (Cursor, VS Code, Claude Code, Codex, Windsurf, Replit, Gemini CLI, OpenCode, Lovable, Bolt, v0, …) rather than deciding which door in the abstract → jump straight to that tool's `plungeai-in-<tool>` skill; it tells you which door that tool uses and gives the exact config. - Same identity behind every door: an `ozk_` key on MCP and the One API, a Studio session cookie (or the same `ozk_` key for key-side verbs) on the CLI. ## Get a key first Self-service `ozk_` keys: **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`) → create → copy it once (shown only at creation). Ask the account owner only if you need a shared team key minted under someone else's account. The same key works on MCP and the One API; the Ocean CLI additionally takes a Studio session cookie for its browser-only surfaces (saved flows, schedules, registry browse). ## Which capability for which job Once you know your door, `plungeai-platform` is the full capability map. Quick router: - **One-shot capability call** ("search the web", "convert this PDF") → `plungeai-agents` (prompt-driven) or `plungeai-tools-connectors` (structured, typed params). - **Multi-step pipeline** ("research A, B, C in parallel, then synthesize") → CNL workflow, author it with `plungeai-workflows`. - **Open-ended goal needing judgment** ("investigate X, use whatever tools you need") → one bounded harness mission, `plungeai-missions`. - **"Every morning / every hour" anything** → `plungeai-scheduling`. - **Long-running lead-gen / outreach style batches** → `plungeai-campaigns`. - **Instruction packs injected into a run** (skills, plugins, experts, personas) → `plungeai-skills-plugins`. - **"Remember this" / long-term memory** → `plungeai-memory`. - **Raw LLM inference in your own code** (chat/embeddings, model fallback) → `plungeai-models`. - **"What can PlungeAI do" / finding an id** → `plungeai-discovery`. - **"Why did that run fail / how long / what did it cost"** → `plungeai-results-traces`. ## Discovery first (every door, non-negotiable) Catalogs are live — the agent registry, tool contracts, model list, and workflow inventory change without notice. Never assert what exists from memory: - MCP: `plungeai_list_agents {search: "<capability>"}` - One API: `GET /v1/discovery/search?q=<capability>`, `GET /v1/agents`, the live contract at `GET /v1/openapi.json` - CLI: `ocean registry lookup <query>` / `ocean agent contract <id>` ## Verify you're in - **MCP:** call `plungeai_whoami` — identity card (user id, tier, key label, rate window). - **One API:** `curl -s https://api.plungeai.com/health` (no auth) proves the router is up; `curl -s https://api.plungeai.com/v1/agents -H "Authorization: Bearer ozk_YOUR_KEY"` proves the key. - **CLI:** `ocean doctor` (exit 0 = ready). ## Related skills - `plungeai-mcp-setup` — connect and operate the MCP server. - `plungeai-api-setup` — auth, first call, OpenAPI, codegen for the One API. - `plungeai-cli-setup` — install, auth, full command reference for `ocean`. - `plungeai-in-<tool>` — per-editor connect steps (Cursor, VS Code, Claude Code, Codex, …). - `plungeai-platform` — the full capability map (agents, tools, workflows, models, missions, scheduling, memory, skills/plugins, observability) once you're connected. # plungeai-api-setup Source: https://docs-preview.plungeai.com/skills/plungeai-api-setup Setup for the PlungeAI One API (https://api.plungeai.com) — a self-service ozk_ key, the base URL, the Bearer/X-API-Key auth header, your first curl call, the live OpenAPI 3.1 contract at /v1/openapi.json, typed-client codegen (openapi-typescript, openapi-python-client, the future @plungeai/one-api), and the shared error-code/rate-limit basics. Use whenever writing or GENERATING code that calls PlungeAI, or answering "how do I authenticate", "where's the OpenAPI spec", or "how do I generate a typed client". Triggers: "PlungeAI API", "api.plungeai.com", "One API", "call plungeai from code", "plungeai openapi", "plungeai curl", "plungeai SDK". Route-by-route capability detail lives in the matching capability skill (`plungeai-models`, `plungeai-agents`, `plungeai-tools-connectors`, `plungeai-workflows`, `plungeai-discovery`, `plungeai-results-traces`) — load one next. MCP calls → `plungeai-mcp-setup`; terminal → `plungeai-cli-setup`; unsure which door → `choose-your-plungeai-door`. [Download zip](https://skills.plungeai.com/plungeai-api-setup.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-api-setup/SKILL.md) One base URL for the whole platform: **`https://api.plungeai.com`**. Plain JSON over HTTPS — no SDK required. The models ("money") plane is OpenAI-compatible. Machine-readable contract: `GET /v1/openapi.json` (OpenAPI 3.1). This skill gets you authenticated and making calls; the route-by-route manual for each capability (what params, what the response looks like, error handling per route) lives in that capability's own skill — load it next. ## Prerequisites — get a key Self-service `ozk_` key: **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`) → create → name it, pick an expiry (never, or 7–365 days) → copy it once, it is shown exactly once and stored hashed thereafter. Ask the account owner only for a shared/team key minted under someone else's account. Keys inherit your account's tier (free by default). The models plane uses a **separate** key with a different prefix, minted at **Dashboard → One API → Keys** (same page, "Model gateway keys" panel): `sk-ocean-YOUR_KEY` for `/v1/chat/completions`, `/v1/embeddings`, `/v1/models` (see `plungeai-models`). Sending the wrong prefix to the wrong plane is a `401`, not a silent fallback — never mix them. ## Discovery first — hard rule The catalog is **live**. Never hardcode agent ids, tool lists, model slugs, or route shapes from memory: - `GET /v1/openapi.json` — the live route contract, no auth required. This is the one authority for what routes exist; regenerate any typed client from it, never patch by hand. - `GET /v1/agents` / `GET /v1/discovery/search?q=<capability>` — what's callable right now (full capability detail: `plungeai-discovery`, `plungeai-agents`). ## Quick start — first call ```bash curl -X POST https://api.plungeai.com/v1/agents/llm-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "Say exactly: hello ocean", "sync": true}' ``` ```json { "content": "hello ocean", "workflow_id": "00000000-0000-4000-8000-000000000001", "task_id": "t1", "request_id": "00000000-0000-4000-8000-000000000004" } ``` That is the whole integration pattern: bearer key, JSON body, JSON result. Every other plane (tools, workflows, models, MCP pass-through, discovery, traces) works the same shape — the per-plane request/response detail is in that plane's capability skill. ## Authentication — header and error basics | Key | Planes | How to send | |---|---|---| | `ozk_YOUR_KEY` | Execution planes: `/v1/discovery`, `/v1/tools`, `/v1/agents`, `/v1/workflows`, `/v1/mcp`, `/v1/traces` | `Authorization: Bearer ozk_YOUR_KEY` (or `X-API-Key: ozk_YOUR_KEY`) | | `sk-ocean-YOUR_KEY` | Models plane: `/v1/chat/completions`, `/v1/embeddings`, `/v1/models` | `Authorization: Bearer sk-ocean-YOUR_KEY` | - Never hardcode keys in generated code — read them from env vars (`PLUNGEAI_API_KEY` for `ozk_`, `PLUNGEAI_INFERENCE_KEY` for `sk-ocean-`). - Execution-plane errors use the envelope `{"error":{"code","message",…}}` — this includes `/v1/discovery/recommend` and `/v1/discovery/cards/:type/:id`, which normalize the registry's own flat `{"error":"<string>"}` rejections into the envelope before you see them (`code` is `not_found` on a 404, `invalid_request` otherwise). The models plane uses the OpenAI error shape (`{"error":{"message","type","code","request_id"}}`). - Every response carries a **server-minted** `x-request-id` header. To correlate your own calls, send **`x-trace-id`** and keep your own copy — it is not echoed back, but it is threaded across every internal hop and queryable at `GET /v1/traces/<your id>` (`plungeai-results-traces`). ## Error semantics — the ones every caller needs | Status | Code | Meaning | What your code does | |---|---|---|---| | 401 | `unauthorized` | Missing/invalid key, or the wrong key prefix for this plane | Fix the key. Never retry in a loop | | 403 | `refused` | **Trust fence.** The agent/tool refused the action outright — a gated/money verb, unattended surface. A policy verdict, not a lifecycle state | **FINAL. Surface verbatim. NEVER retry, rephrase, or route around** | | 403 | `agent_not_active` | A named agent (in a workflow or a single-agent execute) is parked/inactive — a lifecycle state, distinct from `refused` above | Re-discover a fresh id (`GET /v1/discovery/search`); don't retry the same id | | 404 | `unknown_agent` / `unknown_tool` / `workflow_not_found` | No such (or unknown) id | Re-discover; don't retry the same id | | 404 | `not_ready` | Async result not landed yet | Poll again with backoff (2s+) | | 409 | `approval_required` | **Trust fence.** A human must approve before the action runs — implemented and produced today, not a placeholder | Approve out-of-band (Studio, or MCP `plungeai_continue` — the One API itself has no REST `continue` route), then re-issue the identical request | | 422 | `invalid_params` | Outcome `needs_input` — body fails the tool contract; response echoes `missing` and the full contract | Self-correct from the echoed contract, then retry once | | 424 | `connection_required` / `credential_required` | Outcome `needs_connection` / `needs_api_key` — no connected account, or no API key for a connector | Connect the account or add the key (Ocean Studio → Connectors), then retry | | 429 | `rate_limited` | **Execution planes** — per-tier RPM/RPD cap, or failed-auth metering | Honour the `Retry-After` header; back off | | 429 | `rate_limit_exceeded` / `spend_cap_exceeded` / `insufficient_quota` | **Models plane only** — separate codes, separate plane; rate, spend-cap, or quota limit | Back off; caps/quotas are policy, not transients | | 5xx | `engine_error` / `upstream_error` / `internal_error` | Upstream or router failure | One retry with backoff is reasonable | Canonical code list (all planes, every status): `docs/guide-3.0/13-errors-limits.md` §13.2 (execution-plane codes), §13.3 (outcome→HTTP mapping), §13.5 (the two trust-fence statuses). `403 refused` and `409 approval_required` are the fence; everything else is caller-fixable. Sync vs async, per-route detail, and the full route list are in each capability's own skill — this skill only carries the pattern, not the catalog. ## Rate limits Execution-plane tiers: free 30/min · 1,000/day, pro 100/min · 10,000/day, enterprise 300/min · 100,000/day (an unset tier defaults to pro; a per-key override can replace the per-minute cap). Enforced per-key on `POST` executions only (catalog `GET`s are free); a hit answers `429 rate_limited` with a `Retry-After` header — honour it. The models plane has its own, separate limiter, default 600 req/min per key, answering `429 rate_limit_exceeded` with **no** `Retry-After` header — back off on a short fixed interval (~1s) instead. Don't hammer result-polling endpoints; use 2s+ intervals. ## Self-documenting endpoints (no auth) - `GET /v1/openapi.json` — OpenAPI 3.1 contract - `GET /llms.txt` — index (llmstxt.org format) · `GET /llms-full.txt` — full guide + route reference as one markdown payload - `GET /docs` — human docs page - `GET /health` — liveness AI agents at runtime can skip HTTP entirely: connect an MCP client to `https://mcp.plungeai.com/v1` with an `ozk_` key — see `plungeai-mcp-setup`. ## SDK and codegen The supported path is generating a typed client from the live OpenAPI spec — there is no hand-maintained SDK. Full snippets (TypeScript via `openapi-typescript` + `openapi-fetch`, a minimal Python wrapper, the `@plungeai/one-api` shape for when it's published, the curl cookbook, and a paste-ready `AGENTS.md` block for apps you generate): [`references/sdk-and-codegen.md`](/skills/plungeai-api-setup/references/sdk-and-codegen). ## Verify ```bash # 1. Liveness (no auth) — expect {"status":"ok","service":"one-api-router",...} curl -s https://api.plungeai.com/health # 2. Authenticated GET — expect {"tools":[...],"count":N} curl -s "https://api.plungeai.com/v1/tools?limit=1" \ -H "Authorization: Bearer ozk_YOUR_KEY" # 3. A 401 here means the key is wrong; a 200 with cards means you're in: curl -s "https://api.plungeai.com/v1/discovery/search?q=web%20search&limit=1" \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` For the models plane, verify separately with the `sk-ocean-` key: `curl -s https://api.plungeai.com/v1/models -H "Authorization: Bearer sk-ocean-YOUR_KEY"`. ## References - [`references/sdk-and-codegen.md`](/skills/plungeai-api-setup/references/sdk-and-codegen) — typed-client generation (TS/Python), the `@plungeai/one-api` client shape, curl cookbook, self-documenting endpoints, the paste-ready `AGENTS.md` block for generated apps. ## Related skills - `plungeai-models` — the OpenAI-compatible plane in depth: routing, presets, guardrails, caching, pricing. - `plungeai-agents`, `plungeai-tools-connectors` — execute a registry agent or a structured tool; contracts, sync/async, 422 handling. - `plungeai-workflows` — CNL YAML authoring and the workflow execution routes (inline + saved, SSE streaming). - `plungeai-discovery` — catalog search, recommendations, cards. - `plungeai-results-traces` — execution traces, MCP-as-server routes, results/conversation. - `plungeai-mcp-setup` — the same platform over MCP instead of REST. - `plungeai-cli-setup` — operate PlungeAI from a terminal. ## Reference pages <CardGroup cols={2}> <Card title="SDK & codegen — typed clients, snippets, and the AGENTS.md block" icon="file-text" href="/skills/plungeai-api-setup/references/sdk-and-codegen"> The supported integration stance, in order of preference: </Card> </CardGroup> # SDK & codegen — typed clients, snippets, and the AGENTS.md block Source: https://docs-preview.plungeai.com/skills/plungeai-api-setup/references/sdk-and-codegen <!-- sources-of-truth: orchestration/api-gateway/openapi.ts, orchestration/api-gateway/routes/discovery.ts, orchestration/api-gateway/routes/workflows.ts, sdk/one-api-client/README.md, docs/ONE-API-DEVELOPER-GUIDE-2.0.md | last-synced: 2026-09-24 (re-verified: `/v1/workflows/execute-stream` is now a full entry in openapi.ts — the "absent from spec" gap is closed, claim removed; discovery.ts `forward()` normalizes recommend/cards flat registry errors into the standard envelope, so the "passes through raw" claim was stale and is corrected) --> The supported integration stance, in order of preference: 1. **Plain HTTPS** — every plane is JSON over HTTPS; any HTTP client works. 2. **The OpenAI SDK you already use** — for the models plane only (`base_url = https://api.plungeai.com/v1`, `sk-ocean-` key). See the `plungeai-models` skill. 3. **Generate your own client** from the live OpenAPI 3.1 spec — the primary typed path today. 4. **`@plungeai/one-api`** — typed TypeScript client for the execution planes, **when published**. There is no hand-maintained SDK, deliberately: the OpenAPI document at `GET /v1/openapi.json` is the contract, and everything typed is generated from it. ## Generate your own client (any language) The spec is OpenAPI 3.1 at `https://api.plungeai.com/v1/openapi.json`. Any 3.1-capable generator works. **TypeScript**: ```bash npx openapi-typescript https://api.plungeai.com/v1/openapi.json -o src/plungeai-schema.d.ts npm install openapi-fetch ``` ```ts import createClient from 'openapi-fetch' import type { paths } from './plungeai-schema' export const plungeai = createClient<paths>({ baseUrl: 'https://api.plungeai.com', headers: { Authorization: `Bearer ${process.env.PLUNGEAI_API_KEY}` }, }) ``` Re-run the generator when the API changes shape — never patch generated types by hand. One thing to know: `/v1/discovery/recommend` and `/v1/discovery/cards/{type}/{id}` normalize the registry's own flat `{"error":"<string>"}` rejections into the standard envelope (`{"error":{"code","message"}}`, `code` is `not_found` on a 404, `invalid_request` otherwise) before you ever see them — a generated client's error type for these two routes is accurate as-is, no special-casing needed. **Python** — plain `requests` is usually enough; a minimal wrapper: ```python import os, requests class PlungeAI: BASE = "https://api.plungeai.com" def __init__(self, key: str | None = None): self.s = requests.Session() self.s.headers["Authorization"] = f"Bearer {key or os.environ['PLUNGEAI_API_KEY']}" def _call(self, method: str, path: str, **kw): r = self.s.request(method, f"{self.BASE}{path}", **kw) if r.status_code in (403, 409): err = r.json()["error"] # Lifecycle refusals (parked agent / unknown card — the reason says) # are fixable by re-discovering the id; fence refusals are FINAL. if "registry search" in err.get("message", ""): raise LookupError(err) # re-discover the id, then retry raise PermissionError(err) # trust fence — final, never retry r.raise_for_status() return r.json() def execute_agent(self, agent_id: str, prompt: str, sync: bool = True): return self._call("POST", f"/v1/agents/{agent_id}/execute", json={"prompt": prompt, "sync": sync}) def search(self, q: str, **params): return self._call("GET", "/v1/discovery/search", params={"q": q, **params}) ai = PlungeAI() print(ai.execute_agent("llm-agent", "Say exactly: py ok")["content"]) ``` For a fully typed Python client: `openapi-python-client generate --url https://api.plungeai.com/v1/openapi.json`. ## `@plungeai/one-api` — typed TypeScript client **Not yet published to npm** — `npm install @plungeai/one-api` fails today; generate the identical client yourself (previous section — it is the same two libraries). When published, the package is generated from the live `GET /v1/openapi.json` via [`openapi-typescript`](https://openapi-ts.dev); runtime is [`openapi-fetch`](https://openapi-ts.dev/openapi-fetch) (~6KB). The only handwritten code is a ~15-line `createOneApi()` factory. ```ts import { createOneApi } from '@plungeai/one-api' const client = createOneApi({ apiKey: process.env.PLUNGEAI_API_KEY! }) // ozk_YOUR_KEY // GET /v1/tools — response fully typed const { data, error } = await client.GET('/v1/tools', { params: { query: { limit: 10 } }, }) if (data) console.log(data.count, data.tools.map(t => t.id)) // POST /v1/agents/{id}/execute — path params and body typed const { data: exec } = await client.POST('/v1/agents/{id}/execute', { params: { path: { id: 'llm-agent' } }, body: { prompt: 'Say exactly: sdk ok', sync: true }, }) console.log(exec?.content) // "sdk ok" ``` Schema types are exported for reuse: ```ts import type { paths, components } from '@plungeai/one-api' type Card = components['schemas']['Card'] ``` Every `client.GET/POST/DELETE(...)` maps 1:1 to a route in the OpenAPI document. The models plane is not this client's job — use the OpenAI SDK for that. ## curl cookbook Agent/tool ids below (`brave-agent`, `llm-agent`) are illustrative — take real ids from the discovery call two lines up, never from memory. ```bash BASE=https://api.plungeai.com AUTH='Authorization: Bearer ozk_YOUR_KEY' curl -s $BASE/health # liveness, no auth curl -s $BASE/v1/openapi.json | head -50 # live contract, no auth curl -s "$BASE/v1/discovery/search?q=web%20search&limit=3" -H "$AUTH" curl -s "$BASE/v1/tools?limit=5" -H "$AUTH" curl -s $BASE/v1/tools/brave-agent -H "$AUTH" # contract (id from discovery) curl -s -X POST $BASE/v1/agents/llm-agent/execute -H "$AUTH" \ -H 'Content-Type: application/json' -d '{"prompt":"Say: ok"}' curl -s $BASE/v1/traces/REQUEST_ID_FROM_ABOVE -H "$AUTH" ``` ## Self-documenting endpoints The API teaches itself from the domain — useful for onboarding a coding agent with zero prior context: - `GET https://api.plungeai.com/llms.txt` — index (llmstxt.org format) - `GET https://api.plungeai.com/llms-full.txt` — the full developer guide + route reference as one markdown payload - `GET https://api.plungeai.com/v1/openapi.json` — the machine contract - `GET https://api.plungeai.com/docs` — human-readable docs page AI agents at **runtime** can skip HTTP clients entirely: connect an MCP client to `https://mcp.plungeai.com/v1` with an `ozk_` key (see the `plungeai-mcp-setup` skill). ## AGENTS.md block for generated apps When you generate an app that calls PlungeAI, drop this block into the app's `AGENTS.md` (or `CLAUDE.md`) so future coding agents in that repo handle the API correctly. Paste-ready: ```markdown ## PlungeAI One API This app calls the PlungeAI One API at https://api.plungeai.com. - Auth: `Authorization: Bearer $PLUNGEAI_API_KEY` (an `ozk_` platform key) for /v1/discovery, /v1/tools, /v1/agents, /v1/workflows, /v1/mcp, /v1/traces. The OpenAI-compatible models plane (/v1/chat/completions, /v1/embeddings, /v1/models) uses `$PLUNGEAI_INFERENCE_KEY` (an `sk-ocean-` key) instead. Keys live in env vars only — never commit or log them. - Live contract: `GET /v1/openapi.json`. Live catalog: `GET /v1/agents`, `GET /v1/discovery/search?q=...`. Never hardcode agent/tool/model ids or counts — discover them, and re-discover on 404 `unknown_tool` / `workflow_not_found`. - Sync vs async: agent execute defaults to sync; `sync:false` returns 202 + `{workflow_id, task_id}` — poll `GET /v1/agents/results/:wf/:task` (404 `not_ready` is normal in-flight, back off 2s+). - HARD RULE — trust fences: `403 refused` (a gated/money verb refused outright) and `409 approval_required` (a human must approve before the action runs — this is implemented and produced today, not a placeholder) are both final for now — surface them to the user; never retry, rephrase, or route around a `403 refused`. For `409`, approve out-of-band (Ocean Studio, or MCP `plungeai_continue` — the One API alone has no REST `continue` route) and then re-issue the identical request. A separate, unrelated `403 agent_not_active` (a parked/inactive agent id) is a lifecycle state, not a fence — re-discover a fresh id and retry with that instead. - `422 invalid_params` echoes the tool contract — self-correct once, then stop. - Rate limits: execution-plane `429 rate_limited` carries `Retry-After` — honour it. The models plane's separate `429 rate_limit_exceeded` has no Retry-After — use a fixed ~1s backoff there instead. - 502 `upstream_error` / 500 `internal_error` can come from any route — retry once with backoff. - Correlation: send `x-trace-id` on writes; debug via `GET /v1/traces/:id`. - Full docs for agents: `GET https://api.plungeai.com/llms-full.txt`. ``` Keep the block verbatim except the env-var names, which should match the app's conventions. # plungeai-cli-setup Source: https://docs-preview.plungeai.com/skills/plungeai-cli-setup Operate the Ocean CLI (`ocean`; package @plungeai/ocean-cli — not yet on npm, run from the Ocean-Platform repo) to drive PlungeAI from a terminal: install/setup, auth (Studio session cookie vs self-service ozk_ key and which commands need which), running saved workflows and ad-hoc CNL YAML, async runs and status polling, executions/results/exports, schedules, registry lookups, missions, memory, templates, the AI chat REPL and its slash commands, and troubleshooting with `ocean doctor`. Use when the user mentions the `ocean` command or wants PlungeAI operated from a shell or CI script. Triggers: "ocean cli", "ocean command", "plungeai cli", "@plungeai/ocean-cli", "ocean doctor", "ocean workflow run", "run plungeai from terminal", "ocean repl", "ocean shell". NOT for raw HTTP calls (`plungeai-api-setup`), plungeai_* MCP tool calls (`plungeai-mcp-setup`), authoring CNL YAML (`plungeai-workflows`), or wiring other AI tools (`plungeai-in-<tool>`). [Download zip](https://skills.plungeai.com/plungeai-cli-setup.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-cli-setup/SKILL.md) The `ocean` CLI is a **remote client** for the PlungeAI Ocean platform. All execution happens on Cloudflare — the CLI talks HTTPS to three surfaces: | Surface | Host | Credential | |---|---|---| | Studio API (flows, runs, results, schedules, registry, AI chat) | https://studio.plungeai.com | Studio session cookie | | Gateway (ad-hoc YAML execution) | https://api.plungeai.com | API key `ozk_YOUR_KEY` | | MCP platform verbs (whoami, memory, missions, agents, async runs) | https://mcp.plungeai.com/v1 | API key `ozk_YOUR_KEY` (Bearer) | There is no local execution mode. Nothing to run locally except the CLI itself (the optional local-node daemon is separate — `ocean local status`). ## Install Current truth (per `cli/README.md`): the npm package is **not yet published** — the publish is an owner action (tag `ocean-cli-v2.3.0`). ```bash # Working today — from the Ocean-Platform repo root: npm run ocean -- --help # run any command npm link # or: put the `ocean` bin on your PATH # Once published to npm: npm install -g @plungeai/ocean-cli # or: npx @plungeai/ocean-cli ``` Requires Node >= 20. `ocean --version` prints the CLI version (plus platform version when run inside the repo). Full install/config detail: [`references/auth-and-setup.md`](/skills/plungeai-cli-setup/references/auth-and-setup). ## Auth quick start Two independent credentials — the CLI never mixes them (session cookie goes only to Studio; API key only to Gateway/MCP): ```bash ocean auth set-key # hidden prompt — API key (ozk_YOUR_KEY), scripting/agent verbs ocean auth set-session # hidden prompt — Studio auth-session cookie, Studio features ocean login # prints the full cloud auth guide (where to get both) ocean auth status # what's configured ocean doctor # verify every configured credential live (exit 1 on failure) ``` - **Studio session** unlocks: AI chat/REPL, saved flows, runs, results, schedules, registry. Get it: sign in at https://studio.plungeai.com, copy the `auth-session` cookie value. - **API key** (`ozk_YOUR_KEY`) unlocks: `workflow run-yaml`, `workflow run --async`, `whoami`, `memory`, `templates`, `learn`, `mission`, `agent …`. Self-service: **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`) → create → copy it once. - CI/scripts: `OCEAN_API_KEY` env var overrides the config key for the process — but any command that saves CLI state (`workflow run`/`run --async`, `refine`, `chat`, `ocean run`, `observatory run`) writes the merged config back and PERSISTS the env key into `~/.ocean/config.json` (0600). On shared runners use a throwaway `HOME` (`export HOME=$(mktemp -d)`) or finish with `ocean logout`; `whoami`, `doctor`, `run-yaml`, `agent run`, `memory`, `mission` never save. Full detail: [`references/auth-and-setup.md`](/skills/plungeai-cli-setup/references/auth-and-setup). ## Command overview `ocean` with no arguments opens the AI chat REPL. Everything else is noun-grouped subcommands (details + all flags: [`references/commands.md`](/skills/plungeai-cli-setup/references/commands)): | Command | Purpose | Needs | |---|---|---| | `ocean` / `ocean chat` | AI terminal — plain-language flow builder + agentic chat | session | | `ocean setup [--dry-run]` | Install skills for Claude Code/Cursor + custom-command dir | — | | `ocean login` / `logout` / `auth …` | Credential management | — | | `ocean doctor` | Live connectivity + auth checks | — | | `ocean run ["prompt"]` | One-shot AI prompt (`--json`, `-c` continue) or interactive run | session | | `ocean menu` | Pick-a-flow list UI (non-AI) | session | | `ocean shell` | Command shell — subcommands at an `ocean›` prompt | session or key (TTY required) | | `ocean workflow …` | list · show · build · create · update · edit · delete · refine · versions · restore · undo · followup · run · run-yaml | session (`run --async`: key · run-yaml: key preferred, session fallback) | | `ocean execution …` | list · status · show · output · conversation · continue · export · versions · save-version · restore-version | session (status/output: key fallback) | | `ocean observatory run <id>` | Run with live event timeline | session | | `ocean schedule …` | overview · jobs · runs · create · get · update · delete | session | | `ocean registry …` | Browse/search platform registry (agents, skills, mcp, models, …) | session | | `ocean session …` | list · export — Think chat sessions | session | | `ocean whoami` | Identity, tier, rate window | key | | `ocean memory …` | recall · remember · search-runs (long-term memory) | key | | `ocean templates …` | list · show · use workflow templates | key | | `ocean learn <src>` | Distill URL/text into a private skill | key | | `ocean mission "<goal>"` | Bounded autonomous agent run with memory | key | | `ocean agent …` | run · contract · call — one registry agent as a tool | key | | `ocean local status` | Local node daemon health | — | ## Common flows **Run a saved flow and read the result:** ```bash ocean workflow list --search "market" --json # find the id ocean workflow run <id> -i "AI startups" # live SSE stream + result ``` **Async run from a script (API key path):** ```bash ocean workflow run <id> --async -i "ping" # execution id immediately (only -i works with --async) ocean execution status <exec-id> # poll — bounded CI skeleton: references/agent-flows.md ocean execution output <exec-id> # result markdown ``` Key-only sessions get exactly `workflow run --async`, `run-yaml`, `execution status`, `execution output` on the execution surface. `execution list/show/conversation/continue/ export` and `workflow followup` need the Studio cookie — there is no key-side continue or export. **Ad-hoc YAML without saving (API key):** ```bash ocean workflow run-yaml flow.yaml -i "input text" ``` **Create → refine → run lifecycle:** ```bash ocean workflow create "My Flow" flow.yaml --kind workflow # validated + policy-linted ocean workflow refine <id> "add a summary step" # AI one-shot edit ocean workflow undo # restore pre-refine snapshot ``` **Schedule a daily agent job with Slack delivery:** ```bash ocean schedule create "Daily brief" --type agent --target <agent-id> \ --prompt "summarize AI news" --cron "0 9 * * 1-5" --deliver slack:CHANNEL_ID ocean schedule update <job-id> --cron "0 8 * * 1-5" # delivery settings preserved ``` **Everything above also works conversationally:** run `ocean`, then ask in plain language or use slash commands (`/run`, `/results`, `/schedule jobs`, …). REPL guide: [`references/agent-flows.md`](/skills/plungeai-cli-setup/references/agent-flows). ## Discovery first — never hardcode catalogs Agent ids, models, skills, and templates change. Always discover live: - `ocean registry agents` (also: `twins experts skills plugins mcp models providers connectors`) — browse categories - `ocean registry lookup <id-or-name>` — one entry's card - `ocean agent contract <agent-id>` — live operations, params, credential status - `ocean workflow list` / `--kind bot` / `--search <q>` — your saved flows - `ocean templates list` — starter templates - In the REPL: `/registry`, `/flows`, `/agent contract <id>` All `ocean registry …` commands need the Studio session, and category browse is TTY-only — scripts use `ocean registry lookup <query>` (plain list, up to 20 matches). With only an API key there is no CLI verb that lists agents: discover via the One API (`curl -sH "X-API-Key: $OCEAN_API_KEY" 'https://api.plungeai.com/v1/discovery/search?q=<capability>&limit=5'` — see `plungeai-api-setup`) or the MCP `plungeai_list_agents` tool (`plungeai-mcp-setup`), then feed the id to `ocean agent contract` / `ocean agent run`. ## Hard rules - **API keys never in files or argv.** Enter via the hidden prompt (`ocean auth set-key`) or `OCEAN_API_KEY` env in CI. Never commit or echo a key. `auth set-key`/`set-session` take no positional value (a pasted secret errors with "too many arguments") — but nothing else scans argv, and argv IS sent to the platform as `user_request` on every key-side verb, so never place a secret in any command argument. Keys live in `~/.ocean/config.json` (mode 0600) only. - **Session cookie is a secret too** — same handling. - **Relay server output verbatim.** MCP-verb output (`whoami`, `memory`, `mission`, `agent run`, …) is final platform-rendered markdown — print it as-is, don't re-summarize. - **Schedule updates preserve delivery.** `ocean schedule update` does fresh-GET → merge → PUT; passing `--deliver` REPLACES delivery targets. Never hand-PUT a schedule with partial `parameters`. - **Bot policy lint runs at save.** `memory_owner:` is refused; hardcoded emails/UUIDs warn; `--kind bot` requires exactly one `type: harness` task whose mission ends with `task_complete`. - **Workflow YAML authoring** is its own skill — use `plungeai-workflows` for writing CNL YAML; this skill covers running it from the terminal. ## Verify After install or auth changes, always: ```bash ocean doctor # exit code 0 = ready ``` Green checks (each only when the matching credential is set): Config · Auth · Studio reachable · Workflows API (session) · Gateway api.plungeai.com reachable · Gateway API key valid · MCP authenticated. Any ✗ names the fix (`ocean login`, `ocean auth set-key`). For a scripted probe: `ocean whoami --json` (key) or `ocean workflow list --limit 1 --json` (session). ## References | File | Read when | |---|---| | [`references/commands.md`](/skills/plungeai-cli-setup/references/commands) | Full command reference — every command, subcommand, flag, example | | [`references/auth-and-setup.md`](/skills/plungeai-cli-setup/references/auth-and-setup) | Install, config file, credentials, doctor, setup, troubleshooting | | [`references/agent-flows.md`](/skills/plungeai-cli-setup/references/agent-flows) | Running agents/workflows, executions & results, REPL, scripting/CI patterns | ## Related skills - `plungeai-api-setup` — raw HTTP calls to `api.plungeai.com` (what `run-yaml`/`--async` use under the hood). - `plungeai-mcp-setup` — the `plungeai_*` tools the key-side CLI verbs call. - `plungeai-workflows` — CNL YAML authoring (write it here, run it with `run-yaml`). - `choose-your-plungeai-door` — deciding whether the CLI is the right door at all. ## Reference pages <CardGroup cols={2}> <Card title="Ocean CLI — agent flows, REPL, and scripting" icon="file-text" href="/skills/plungeai-cli-setup/references/agent-flows"> All execution happens on Cloudflare; the CLI streams or polls remotely. </Card> <Card title="Ocean CLI — install, auth, and setup" icon="file-text" href="/skills/plungeai-cli-setup/references/auth-and-setup"> The npm package @plungeai/ocean-cli (v2.3.0, bin name ocean, Node >= 20) is not yet published — publishing is an owner action (pushing the ocean-cli-v2.3.0… </Card> <Card title="Ocean CLI — full command reference" icon="file-text" href="/skills/plungeai-cli-setup/references/commands"> Every command below exists in cli/src/index.ts (Commander registration) and is implemented under cli/src/commands/. </Card> </CardGroup> # Ocean CLI — agent flows, REPL, and scripting Source: https://docs-preview.plungeai.com/skills/plungeai-cli-setup/references/agent-flows <!-- sources-of-truth: cli/README.md, cli/CLAUDE.md, cli/src/commands/workflow.ts, cli/src/commands/chat.ts, cli/src/lib/slash-commands.ts, cli/src/lib/custom-commands.ts, cli/src/lib/mcp-client.ts | last-synced: 2026-09-24 (re-verified: --async only honors -i, --inputs/--json silently ignored, against cli/src/commands/workflow.ts workflowRunCommand — matches, no drift found) --> ## Running agents and workflows from the terminal All execution happens on Cloudflare; the CLI streams or polls remotely. ### Saved flow, live stream (Studio session) ```bash ocean workflow run <id> -i "AI startups in fintech" ocean workflow run <id> --inputs inputs.json # named inputs (flat string map) ocean observatory run <id> -i "query" # event-timeline view instead ``` The stream ends with the formatted result. If the flow is a conversational agent that pauses (a question or a payment approval), the CLI prints it and prompts you inline — the run continues in place until final. Non-interactive shells get a resume hint (`ocean execution continue <id>`) instead. ### Async dispatch + poll (API key) ```bash ocean workflow run <id> --async -i "ping" # prints execution id immediately ocean execution status <exec-id> # queued/running/completed (+ ⏸ block if paused) ocean execution output <exec-id> # result markdown when completed ``` `--async` supports only `-i` (single input) — `--inputs` and `--json` are silently ignored on the async path; named inputs need a sync `workflow run` or Studio. The execution id is also remembered as `last_execution_id` for follow-ups (a config save — see the key-persistence note under Scripting). ### Ad-hoc YAML, nothing saved (API key preferred) ```bash ocean workflow run-yaml flow.yaml -i "input text" ``` With a key: executes through https://api.plungeai.com (One API + result redemption). With only a session it falls back to Studio's execute proxy and prints the raw engine envelope JSON instead of redeemed markdown. `{input}` in the YAML receives `-i`. Author the YAML with the `plungeai-workflows` skill; test with `run-yaml` before `ocean workflow create`. ### One registry agent as a tool (API key) ```bash ocean agent contract exa-agent # discover operations + params ocean agent run exa-agent "latest Cloudflare Workers news" ocean agent call exa-agent search --params '{"query":"cloudflare workers"}' ``` ### Bounded autonomous mission (API key) ```bash ocean mission "find the three strongest competitors to X and compare pricing" \ --max-iter 5 --criteria "table with sources" --sync ``` Without `--sync` the mission dispatches async and the CLI polls every 5s (600s cap, then exit 1). The waiter declares the run terminal when completed/failed/cancelled/error appears ANYWHERE in the status text — not just the `**Status:**` field — so a workflow name containing "failed" or "error" ends the wait on the first poll and the result is fetched prematurely. Prefer `--sync` for short missions; keep those words out of goals; for long missions poll `ocean execution status <id>` yourself and match the `**Status:**` line. ## Results, threads, follow-ups ```bash ocean execution list -l 10 # recent runs ocean execution conversation <id> # full thread: input → result → follow-ups ocean workflow followup <wf-id> "and by region?" # ask about the last run (-e picks another) ocean execution continue <id> # answer a pending question ocean execution continue <id> --approve # approve a pending action ocean execution export <id> -f docx -o report.docx ocean execution save-version <id> "pre-edit" # snapshot; restore-version to roll back ``` Everything in this block except `execution status`/`output` needs the Studio session — a key-only script cannot list, continue a paused run, follow up, or export. ## The AI terminal (REPL) `ocean` (no args) opens the chat REPL — the same harness agent Studio uses. Plain language works for both **building** ("build a workflow that watches the market") and **acting on your account** ("show my ten last runs", "export the last result as docx", "what's on my schedule this week?"). Mutating actions ask for confirmation; when a decision is yours, the agent asks a structured question you answer inline. Type `/help` for the grouped palette. Slash commands mirror the CLI noun groups: | Group | Commands | |---|---| | Workflow agents | `/flows` `/folders` `/bots` `/show` `/run` `/create` `/save` `/run-yaml` `/refine` `/edit` `/versions` `/restore` `/undo` `/delete` | | Runs & results | `/runs` `/results` (`/results inline [N]`) `/results agent` `/results folder` `/followup` `/thread` | | Schedules | `/schedule` `/schedule jobs` `/schedule runs` | | Platform | `/registry` `/agent` `/mission` `/memory` `/templates` `/learn` `/whoami` `/local` | | Session & settings | `/help` `/sessions` `/continue` `/export` `/new` `/mode` `/depth` `/details` `/voice` `/doctor` `/exit` | Legacy names stay as aliases (`/plans` and `/plan-generate` are retired stubs that only print a hint to use `/create` or `/new`): `/agentflows`→`/flows`, `/workflow(s)`→`/flows`, `/agentfolder`→`/folders`, `/executions`→`/runs`, `/resultbyagent`→`/results agent`, `/resultbyfolder`→`/results folder`, `/schedulejobs`→`/schedule jobs`, `/scheduleruns`→`/schedule runs`, `/build`→`/create`, `/tweak`→`/edit`. REPL behaviors worth knowing: - `/create [name]` runs Agentic Build on the current Think conversation — chat the design first, then `/create Market Monitor`. - `/save <name>` saves the YAML block from the last AI reply; `/run-yaml` executes it ad hoc. - `/results` opens a fast metadata-only picker (paginated, Esc exits). Plain requests like "show me my last five results" open the same local picker with no AI round-trip. - `/mode research|plan|build` and `/depth quick|standard|deep|ultra` persist to config; `/details` toggles the SSE tool trace. - Voice: **Ctrl+T** push-to-talk in the prompt; `/voice` modal mic (Enter to stop); `/voice on|off` speaks replies aloud. Recording needs `sox`. - `/edit` uses an inline terminal YAML editor; Ctrl+E opens `$OCEAN_EDITOR` (set it to a terminal editor if `$EDITOR` is a GUI app). - `/exit` (or Ctrl+C) quits. ### Custom slash commands Markdown files in `~/.ocean/commands/` become REPL commands (built-in names can't be shadowed): ```markdown --- description: Review workflow for missing agents target: refine # chat | refine depth: standard # quick | standard | deep | ultra --- Review this workflow for missing error handling and suggest improvements. Focus on: $ARGUMENTS ``` `$ARGUMENTS` receives everything typed after the command; `$1`, `$2`, … receive positional words. `target: refine` applies the prompt as a workflow refine; `target: chat` (default) sends it as a chat turn. ### Command shell (non-AI) `ocean shell` gives an `ocean›` prompt that runs plain subcommands (`workflow list`, `execution output <id>`, …) without re-invoking the binary — handy for exploratory sessions without the AI. ## Scripting and CI patterns - **Inject the key via env, never argv** — but know that `OCEAN_API_KEY` only overrides the config key for the process: any command that saves CLI state (`workflow run`/`run --async`, `refine`, `chat`, `ocean run`, `observatory run`) writes the merged config back and PERSISTS the env key into `~/.ocean/config.json` (0600). On shared or persistent runners use a throwaway `HOME` (`export HOME=$(mktemp -d)`) or finish with `ocean logout`; `whoami`, `doctor`, `run-yaml`, `agent run`, `memory`, `mission` never save. - **Kill ANSI color in CI:** with `$CI` set the CLI force-enables color even when piped — escape codes break word-boundary greps like `\bcompleted\b`. Export `NO_COLOR=1` for anything you parse, or use `--json` (never colored). - **Force non-interactive output:** pass any flag to `workflow list` (`--json`, `--limit`, `--kind`, `--search`); give explicit ids instead of relying on pickers; prefer `--json` where offered (`whoami`, `workflow list`, `execution status`, `schedule get/create/update`, `workflow run --json`, `ocean run "<prompt>" --json`). Caveat: `whoami --json` and key-path `execution status --json` wrap platform markdown in a single JSON string field — you still parse the markdown inside. - **Gate on exit codes — with one asymmetry:** exit codes are 0/1 only. Sync `workflow run` exits 1 when the run itself errors, but `execution status`/ `output` of a FAILED run exit 0 (they successfully report the failure) — an async CI gate must parse the status value (skeleton below). `ocean doctor` is the canonical preflight gate. - **Destructive confirms:** `workflow delete`/`restore`/`undo` prompt `[y/N]` with no `--yes` flag — in scripts pipe `echo y | ocean workflow delete <id>`; an EOF answer cancels with exit 0, so the script "succeeds" without deleting. - **One-shot AI in a script:** `ocean run "summarize this week's runs" --json` → `{content, conversationId}`; `-c` continues the same conversation next call. Async run-and-wait skeleton (bounded, failure-gated, status-FIELD match): ```bash set -euo pipefail export NO_COLOR=1 out=$(ocean workflow run "$WORKFLOW_ID" --async -i "$INPUT") exec_id=$(printf '%s' "$out" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|exec-[[:alnum:]-]+' | head -1) [ -n "$exec_id" ] || { echo "no execution id"; exit 1; } status="" for i in $(seq 1 120); do # 10 min cap st=$(ocean execution status "$exec_id" 2>&1 || true) status=$(printf '%s' "$st" | grep -oiE 'Status:\*{0,2} *(completed|failed|cancelled|error)|^(completed|failed|cancelled|error)\b' | grep -oiE 'completed|failed|cancelled|error' | head -1 || true) [ -n "$status" ] && break sleep 5 done [ "$status" = "completed" ] || { echo "run ended: ${status:-timeout}"; exit 1; } ocean execution output "$exec_id" ``` Match the status FIELD, never the whole line — the status line embeds the workflow NAME (Studio path: `<status> <workflow_name>`; MCP path: `**Workflow:** <name>`), so a flow named "Failed Payments Monitor" would terminate a whole-line grep on the first poll. CI preflight: ```bash ocean doctor || exit 1 ocean whoami --json # {"whoami":"<markdown>"} — one string field; grep it for the expected user/tier ``` ## Rules when driving the CLI as an agent - Discover ids live (`ocean registry …`, `ocean workflow list`, `ocean agent contract <id>`) — never invent agent or workflow ids. - Relay platform-rendered output verbatim; don't re-summarize `whoami`, `memory`, `mission`, or `agent run` results. - Test YAML with `run-yaml` before saving; expect the save lint to refuse `memory_owner:` and to require bots (`--kind bot`) to be exactly one `type: harness` task whose mission ends with `task_complete`. - Update schedules only through `ocean schedule update` (fresh-GET → merge → PUT keeps delivery targets intact); `--deliver` on update REPLACES targets. # Ocean CLI — install, auth, and setup Source: https://docs-preview.plungeai.com/skills/plungeai-cli-setup/references/auth-and-setup <!-- sources-of-truth: cli/README.md, cli/src/lib/ocean-config.ts, cli/src/commands/auth.ts, cli/src/commands/doctor.ts, cli/src/commands/setup.ts, cli/src/lib/login.ts, cli/package.json | last-synced: 2026-09-24 (re-verified: version 2.3.0 + publish trigger against cli/README.md and package.json — matches; fixed a stale "Dashboard → API Keys" UI label to Dashboard → One API → Keys per apps/ocean-dashboard/src/nav.ts) --> ## Install The npm package `@plungeai/ocean-cli` (v2.3.0, bin name `ocean`, Node >= 20) is **not yet published** — publishing is an owner action (pushing the `ocean-cli-v2.3.0` tag triggers the publish workflow). Current truth from `cli/README.md`: ```bash # Working today — from the Ocean-Platform repo root: npm run ocean -- --help # run any command through the repo npm run build:cli # optional: build dist for ~40ms startup npm link # or: put the `ocean` bin on your PATH # Once published to npm: npm install -g @plungeai/ocean-cli # or without installing: npx @plungeai/ocean-cli --help ``` Verify: `ocean --version` (inside the repo it appends the platform version). The linked `ocean` bin prefers `cli/dist/index.js` whenever it exists — after updating the repo, rerun `npm run build:cli` (or delete `cli/dist`) or the bin silently executes the stale build. `npm run ocean --` always runs current source. ## The two credentials The CLI keeps credentials strictly separated — the Studio cookie is only ever sent to Studio; the API key only to the Gateway and MCP server. | Credential | Format | Unlocks | Set with | |---|---|---|---| | Studio session | `auth-session` cookie value | AI chat/REPL, saved flows, runs, results, exports, schedules, registry, sessions | `ocean auth set-session` | | API key | `ozk_YOUR_KEY` | `workflow run-yaml`, `workflow run --async`, `whoami`, `memory`, `templates`, `learn`, `mission`, `agent …` | `ocean auth set-key` | ### Get a Studio session 1. Sign in at https://studio.plungeai.com 2. Copy the `auth-session` cookie value from your browser (devtools → Application/Storage → Cookies). 3. `ocean auth set-session` — hidden prompt. Pasting the whole `auth-session=…` fragment also works; the CLI extracts the value. ### Get an API key 1. Self-service: **Ocean Dashboard → One API → Keys** (`https://dashboard.plungeai.com`) → create a key → name it, pick an expiry (never, or 7–365 days) → copy it once (`ozk_YOUR_KEY` — it is shown exactly once and stored hashed). Ask the account owner only for a shared/team key minted under someone else's account. 2. `ocean auth set-key` — hidden prompt. The CLI refuses values that don't start with `ozk_`. `ocean login` prints this whole guide in the terminal. `ocean auth status` shows what's configured plus a live Studio health probe. `ocean logout` clears both credentials and cached conversation/refine/execution state. ## Key handling rules (hard) - Keys and cookies are entered ONLY via hidden prompts or the `OCEAN_API_KEY` env var. Never on argv: `auth set-key`/`set-session` take no positional value (a pasted secret errors with Commander's "too many arguments"), but nothing else scans argv — and argv IS sent to the platform as `user_request` on every key-side verb — so keep secrets out of all command arguments, shell history, repos, and committed `.env` files. - Storage: `~/.ocean/config.json`, written with mode `0600`. - CI / ephemeral use: `export OCEAN_API_KEY=ozk_YOUR_KEY` — the env override wins over the config file for the process, **but it is persisted on the next state save**: any command that saves CLI state (`workflow run`/`run --async`, `refine`, `chat`, `ocean run`, `observatory run`) writes the merged config — env key included — back to `~/.ocean/config.json` (0600). On shared or persistent runners use a throwaway `HOME` (`export HOME=$(mktemp -d)`) or finish with `ocean logout`. Verbs that never save: `whoami`, `doctor`, `run-yaml`, `agent run`, `memory`, `mission`. ## Config file — `~/.ocean/config.json` Created on first save; JSON, mode 0600. Fields you may care about: | Field | Meaning | Default | |---|---|---| | `studio_url` | Studio origin | `https://studio.plungeai.com` | | `api_gateway_url` | Gateway origin | `https://api.plungeai.com` | | `mcp_url` | MCP server for key-side verbs | `https://mcp.plungeai.com` | | `shared_memory_url` | SharedMemory host for stream pointer polling (rarely overridden) | platform default | | `access_token` | Studio session cookie value | — | | `api_key` | `ozk_YOUR_KEY` | — | | `chat_mode` / `chat_depth` | REPL defaults (`research|plan|build`, `quick|standard|deep|ultra`) | build / deep | | `conversation_id`, `last_execution_id`, `refine_workflow_id`, `refine_undo` | Session state the CLI maintains | — | | `voice_replies` | `/voice on|off` persisted | off | | `node_id`, `admin_port` | Local node daemon (for `ocean local status`) | — | Requests to a stale decommissioned gateway host are transparently redirected to `https://api.plungeai.com` at request time only — the file itself (and the `ocean auth status` display) keeps the old value until the next save. Don't hand-edit around it. ## `ocean setup` One command prepares coding-agent integration: ```bash ocean setup # install; then runs doctor ocean setup --dry-run # list what would be installed, write nothing ``` What it does: 1. Installs the canonical **plungeai-workflows** skill live from https://mcp.plungeai.com (fetches the file list from `/llms.txt`) into `~/.claude/skills/` — and `~/.cursor/skills/` when a `~/.cursor` dir exists. 2. Creates `~/.ocean/commands/` for custom REPL slash commands. 3. Links bundled CLI skills into `~/.cursor/skills/`. 4. Prints the one-click install pointers from the platform install page. 5. Runs `ocean doctor`. Note: the bundled trio is `ocean-cli-lifecycle`, `ocean-cli-workflow`, `ocean-observatory` (from `cli/skills/`) — `ocean setup` does NOT install or update this `plungeai-cli-setup` skill. ## `ocean doctor` — the verification command Run after every install or credential change; it exercises each configured credential against the live platform and sets exit code 1 on any failure: | Check | Probe | Runs when | |---|---|---| | Config | `~/.ocean/config.json` + Studio URL | always | | Auth | session or key present | always | | Studio | health endpoint reachable | any credential set | | Workflows API | authenticated list call | session set | | Gateway | https://api.plungeai.com health | key set | | Gateway API key | key accepted | key set | | MCP | `plungeai_whoami` over https://mcp.plungeai.com/v1 (Bearer key) | key set | All-green ends with "Ready to run workflows". Each ✗ names its fix. Caveat: the session probe runs first in the same chain — if it throws (expired cookie), doctor records "Studio API ✗" and SKIPS the Gateway/MCP checks even when a valid key is set. Doctor also tips: if `$EDITOR` is a GUI app, `/edit` uses the inline terminal editor; set `OCEAN_EDITOR=nano` (or another terminal editor) for Ctrl+E external editing. ## Troubleshooting | Symptom | Fix | |---|---| | `Not authenticated` | `ocean login`, then set a credential | | `A Studio session is required for this command` | `ocean auth set-session` — API keys only cover the key-side verbs | | 401 / "key rejected" on Gateway or MCP | Key revoked or mistyped — mint a new one at Dashboard → One API → Keys, `ocean auth set-key` | | Studio calls fail after working earlier | Session cookie expired — sign in again, `ocean auth set-session` | | `API key must start with ozk_` | You pasted something else (cookie? bearer header?) — copy the raw key | | Doctor Gateway ✗ but Studio ✓ | Key-side config issue; re-run `ocean auth set-key`, check `api_gateway_url` is `https://api.plungeai.com` | | Voice recording does nothing | Recording needs `sox` (`brew install sox`); spoken replies work without it | | Doctor shows only "Studio API ✗" and no Gateway/MCP rows | The expired session aborted the check chain — re-set the session (or `ocean logout` + set only the key) and rerun | | Scripts hang at a prompt | You hit an interactive picker — pass flags (`--json`, `--limit`, ids) to force non-interactive output. Exception: `ocean registry` browse has no flags and is a no-op when piped — use `ocean registry lookup <query>` | | CI output full of escape codes / greps miss | `$CI` force-enables ANSI color even without a TTY — export `NO_COLOR=1` or use `--json` | Escalation path: `ocean doctor` → `ocean auth status` → re-set the failing credential → `ocean doctor` again (exit 0 = done). # Ocean CLI — full command reference Source: https://docs-preview.plungeai.com/skills/plungeai-cli-setup/references/commands <!-- sources-of-truth: cli/src/index.ts, cli/src/commands/*.ts, cli/src/lib/ocean-config.ts, cli/README.md | last-synced: 2026-09-24 (re-verified: workflow run --async input-only behavior against workflow.ts, schedule deliver channel parsing (incl. Slack "C" prefix) against schedule-create.ts/schedule-params.ts, scheduler delivery.ts channel list — all match, no drift found) --> Every command below exists in `cli/src/index.ts` (Commander registration) and is implemented under `cli/src/commands/`. Global flags: `-h/--help` on any command, `-V/--version` on the root. Running `ocean` with **no arguments** opens the AI chat REPL. Credential legend: **[session]** = Studio session cookie required · **[key]** = API key (`ozk_YOUR_KEY`) required · **[—]** = works unauthenticated. ## Top-level ### `ocean setup [--dry-run]` [—] Installs the canonical `plungeai-workflows` skill live from https://mcp.plungeai.com into `~/.claude/skills/` (and `~/.cursor/skills/` when Cursor is present), creates `~/.ocean/commands/` for custom slash commands, links bundled CLI skills into Cursor, prints the platform install-page pointers, then runs `ocean doctor`. - `--dry-run` — print what would be installed without writing. ### `ocean chat` [session] AI chat REPL (identical to bare `ocean`). See [`references/agent-flows.md`](/skills/plungeai-cli-setup/references/agent-flows). ### `ocean login` [—] Prints the cloud auth guide: how to get a Studio session cookie and an API key, and which command saves each. Does not open a browser — everything runs on Cloudflare; the CLI is a remote client only. ### `ocean logout` [—] Clears saved session, API key, and conversation/refine/execution state from `~/.ocean/config.json`. ### `ocean doctor` [—] Live health checks; sets exit code 1 when any check fails. Checks (each auth probe only when that credential is configured): Config · Auth · Studio reachable · Workflows API (session) · Gateway (https://api.plungeai.com) reachable · Gateway API key valid · MCP (https://mcp.plungeai.com) authenticated. ### `ocean whoami [--json]` [key] Server-side identity over the MCP path: user id, tier (e.g. pro), rate window, key name. `--json` prints `{"whoami":"<platform markdown>"}` — one string field, not structured data; parse the markdown inside for user/tier. ### `ocean memory <action> [arg]` [key] Long-term platform memory. - `ocean memory recall [query]` — read memory (optionally filtered). - `ocean memory remember` — bare = read; with one of: - `--add "<text>"` — append a memory line - `--replace "<old>" "<new>"` — exactly two values - `--remove "<text>"` — remove a line - `--target user|memory` — which store (default `user`) - `ocean memory search-runs "<query>" [--limit N]` — search past run results. ### `ocean templates [action] [id]` [key] Workflow templates. - `ocean templates list [--category <cat>] [--limit N]` - `ocean templates show <id>` - `ocean templates use <id> [--name <name>] [--folder <name>]` — instantiate as a saved workflow. ### `ocean learn <source> [--name <id>]` [key] Distill a URL or literal text into a private platform skill. `--name` sets the kebab-case skill id. ### `ocean mission "<goal>"` [key] Bounded autonomous agent run with memory (async + poll by default). - `--mission <purpose>` — mission purpose statement - `--tools <a,b,c>` — allowed tools, comma-separated - `--max-iter <n>` — iteration cap - `--criteria "<c>"` — success criteria, repeatable - `--persona <id>` — persona card id - `--skills <a,b>` — skill card ids, comma-separated - `--sync` — wait inline instead of async+poll Without `--sync`: polls every 5s up to 600s (then exit 1); the waiter treats completed/failed/cancelled/error ANYWHERE in the status text as terminal — not just the `**Status:**` field — so those words in a workflow name end the wait early. Prefer `--sync` for short missions. ### `ocean agent …` [key] Registry agents as tools. - `ocean agent run <agentId> "<prompt>" [--model <m>] [--session <id>]` — one agent, one prompt (optionally in a conversation session). - `ocean agent contract <agentId>` — invocation contract: operations, params, live credential status. - `ocean agent call <agentId> [operation] [--params '{"k":"v"}'] [--prompt "<text>"]` — typed tool execution against a contract operation. ### `ocean local status [--json]` [—] Local node daemon health on this machine (uses config `node_id`/`admin_port`). ### `ocean menu` [session] Interactive pick-a-flow menu (non-AI). ### `ocean run [message...]` [session] - No message: interactive flow run (picker). - With message: one-shot AI prompt, streamed. Flags: - `-c, --continue` — continue the last AI conversation - `-m, --mode research|plan|build` - `-d, --depth quick|standard|deep|ultra` - `--json` — print `{content, conversationId}` JSON (for scripts) ### `ocean shell` [session or key] Command shell: type any `ocean` subcommand at an `ocean›` prompt (parse errors recover instead of exiting). Requires a TTY and at least one credential. ## `ocean auth` - `ocean auth status` [—] — Studio/Gateway URLs, whether session and key are set, live Studio health. - `ocean auth set-key` [—] — hidden prompt; value must start with `ozk_`; saved to `~/.ocean/config.json` (0600). - `ocean auth set-session` [—] — hidden prompt; accepts the raw cookie value or a pasted `auth-session=…` fragment. ## `ocean workflow` — agent flows [session unless noted] - `ocean workflow list` — interactive picker by default; **any flag switches to non-interactive output**: `--kind workflow|agent|bot` · `--limit N` · `--search <q>` (server-side name search) · `--folder <name>` · `--json`. Rows include a kind column. - `ocean workflow show [query] [--yaml]` — look up by id, name, or picker; `--yaml` prints the flow YAML. - `ocean workflow build [thinkId] [-n <name>]` — Agentic Build from a Think chat session (Studio parity). - `ocean workflow create <name> <file.yaml> [-d <desc>] [--kind workflow|agent|bot] [--json]` — save from a YAML file. CNL-validated + policy-linted: `memory_owner:` refused, hardcoded emails/UUIDs warn, `--kind bot` requires exactly one `type: harness` task whose mission ends with `task_complete`. - `ocean workflow update <id> [-f|--file <file.yaml>] [-n <name>] [--description <text>]` - `ocean workflow edit <id>` — edit session: YAML editor, refine, run, until Esc. (`ocean workflow tweak <id>` is a kept alias.) - `ocean workflow delete <id>` - `ocean workflow refine <id> "<what to change>" [-d <depth>] [--json]` — AI one-shot edit in plain English. - `ocean workflow versions <id>` — version history. - `ocean workflow restore <id> <versionRef>` — version number or id prefix. - `ocean workflow undo [id]` — restore the pre-refine snapshot. `delete`/`restore`/`undo` prompt `[y/N]` with no `--yes` flag — in scripts pipe `echo y | ocean workflow delete <id>`; an EOF answer cancels with exit 0 (the script "succeeds" without deleting). - `ocean workflow followup <id> "<prompt>" [-e|--execution <executionId>]` — follow-up question on a completed execution (default: last run). - `ocean workflow run <id>` — run with live SSE output, then result + any pending question/approval continuation. Flags: - `-i, --input "<text>"` — single input value - `--inputs <file.json>` — named inputs (flat JSON object, string values); mutually exclusive with `--input` - `--json` — raw SSE events as JSON lines - `--async` **[key]** — dispatch via the MCP surface and return the execution id immediately; prints a `poll: ocean execution status <id>` hint. Only `-i` is honored with `--async` — `--inputs` and `--json` are silently ignored on the async path (named inputs need a sync run or Studio). - `ocean workflow run-yaml <file> [-i "<input>"]` **[key preferred; session fallback]** — execute ad-hoc YAML (nothing saved). With a key: via https://api.plungeai.com (`POST /v1/workflows/execute` + result redemption). With only a session: falls back to Studio's execute proxy and prints the raw engine envelope JSON, no redeemed markdown. `{input}` placeholder receives `-i`. ## `ocean session` — Think chat sessions [session] - `ocean session list` — list conversations. - `ocean session export [file]` — export the current conversation to markdown (requires an active conversation from `ocean chat`). ## `ocean registry` — platform discovery [session] Registry data loads live from the platform discovery service — never a static catalog. - `ocean registry` — browse everything. - `ocean registry <category> [subtype]` — categories: `agents` `twins` `experts` `skills` `plugins` `mcp` `models` `providers` `connectors`. - `ocean registry lookup <query…>` / `ocean registry show <query…>` — one entry's card. - `ocean registry <free text>` — direct lookup shorthand. Non-TTY: category browse (`ocean registry`, `ocean registry agents`) prints only "Registry browse requires an interactive terminal" and exits 0 — a no-op for scripts. `ocean registry lookup <query>` DOES work non-interactively (exact card, or a plain list of up to 20 matches); key-only discovery goes through the One API discovery search instead (`plungeai-api-setup` skill). ## `ocean schedule` — scheduled jobs [session] - `ocean schedule` / `ocean schedule overview` — jobs + today stats. - `ocean schedule jobs` — browse jobs (picker in a TTY, plain list when piped). - `ocean schedule runs` — run history. - `ocean schedule create <name> --type agent|query|workflow|heartbeat --cron "<expr>"` — agent/query jobs are wrapped as one-task workflows. Options: - `--target <id>` — agent id (agent/query) or workflow id (workflow) - `--prompt "<text>"` — what the agent does each run (`--query` is an alias for `--type query`) - `--mission-ref <id>` — pre-built agent card id (schedules a harness wrapper) - heartbeat only: `--check-agent <id>` · `--condition "<prompt>"` · `--trigger <workflowId>` · `--notify telegram|whatsapp|discord|slack|email` · `--notify-to <target>` - `--deliver <channel:to>` — repeatable delivery targets. Channels: `telegram:<chat-id>` · `whatsapp:<number>` · `discord:<chat-id>` · `slack:<target>` · `email:a@b.c` · `inapp` (no target). Slack values starting with `C` are treated as channel ids; anything else as a member id/handle. - `--local` — mark for local-node execution - `--description "<text>"` · `--json` - `ocean schedule get <id> [--json]` — one job including delivery targets. - `ocean schedule update <id>` — **fresh-GET → merge → PUT; delivery settings preserved** unless `--deliver` is passed (which REPLACES them). Options: `--cron` · `--name` · `--description` · `--prompt` · `--deliver …` · `--status active|paused` · `--json`. - `ocean schedule delete <id>` — soft delete (history preserved). Removes only the job: agent/query/mission-ref jobs leave their auto-created wrapper workflow "Scheduled: <name>" in your flows — `ocean workflow delete <id>` it separately if you want it gone. Example: ```bash ocean schedule create "Weekday brief" --type agent --target research-agent \ --prompt "top AI news, 5 bullets" --cron "0 9 * * 1-5" \ --deliver slack:CHANNEL_ID --deliver email:me@example.com ``` ## `ocean execution` — runs & results [session unless noted] Only `status` and `output` have API-key fallbacks; everything else here — including `continue` and `export` — is session-only with no key path (a key-only script cannot continue a paused run or export). - `ocean execution list [-w|--workflow <workflowId>] [-l N]` — recent runs (limit default 20, must be a positive integer). - `ocean execution status <id> [--json]` **[session or key]** — one-line status; when the run is paused on a question/approval, the ⏸ block is relayed verbatim (the printed `continue … --approve` hint is itself session-only). Falls back to the MCP key path for gateway-dispatched runs. `--json` shape differs by path: Studio = full execution JSON (`.status` field); key/MCP = `{"execution_id","status_text":"<markdown>"}` — parse the `**Status:**` line inside `status_text`. - `ocean execution show <id>` — metadata. - `ocean execution output <id>` **[session or key]** — result markdown (MCP key fallback for gateway-dispatched runs). Rendered terminal-formatted (wrapped, `── Output ──` header, pager for long results in a TTY); there is no raw-markdown flag — for byte-exact artifacts use `execution export` (session), or parse the wrapped text with `NO_COLOR=1`. - `ocean execution conversation <id>` — full multi-turn thread (input → result → follow-ups). - `ocean execution continue <id> [--approve]` — resume a paused conversation: answer the pending question (prompted) or approve the pending action. - `ocean execution export <id> -f|--format <fmt> [-o|--out <file>] [--models <list>]` — formats: `docx` · `pptx` · `xlsx` · `finmodel` · `pdf` · `package` · `google-docs`. `--models` selects FinModel types. - `ocean execution versions <id>` — saved result snapshots. - `ocean execution save-version <id> ["note"]` - `ocean execution restore-version <id> <version>` — number or version id. ## `ocean observatory` [session] - `ocean observatory run <workflowId> [-i "<input>"] [--inputs <file.json>]` — run with an Observatory-style live event timeline instead of the plain stream. ## Validation & error behavior - Numeric flags like `-l/--limit` reject non-positive/non-integer values. - Choice flags (`--mode`, `--depth`) reject values outside their set. - `auth set-key`/`set-session` take no positional value — a pasted secret dies with Commander's "too many arguments". Nothing else scans argv, and argv is sent to the platform as `user_request` on every key-side verb — keep secrets out of all command arguments (hidden prompts / `OCEAN_API_KEY` only). - A 401 from any surface prints a friendly hint (`ocean login` / `ocean auth set-key`) instead of a stack trace. - Exit codes are 0/1 only. Failures exit 1 (`ocean doctor` included), and sync `workflow run` exits 1 when the run itself reports a workflow error — but `execution status`/`output` of a FAILED run exit 0 (they successfully report the failure; `output` prints a "_No stored markdown output_" notice). Async CI gates must parse the status value, not the exit code. # plungeai-mcp-setup Source: https://docs-preview.plungeai.com/skills/plungeai-mcp-setup Connect and operate the PlungeAI MCP server (https://mcp.plungeai.com/v1) — endpoint and Bearer ozk_/X-API-Key auth, a generic MCP client config (native remote/HTTP, or the mcp-remote stdio bridge), plungeai_whoami, the structured-outcome envelope and trust fences, the full plungeai_* tool index pointing to the capability skill for each tool, and connection troubleshooting. Use when connecting ANY MCP client to PlungeAI, calling or planning plungeai_* tool calls, polling an execution, resuming a paused run (plungeai_continue), or debugging a 401, a short tool list, or a fenced key. Triggers: "plungeai MCP", "mcp.plungeai.com", "connect an MCP client", "plungeai_whoami", "needs_approval", "execution id". Per-editor install steps live in `plungeai-in-<tool>` — load that instead. REST/codegen is `plungeai-api-setup`; terminal is `plungeai-cli-setup`; CNL authoring is `plungeai-workflows`. [Download zip](https://skills.plungeai.com/plungeai-mcp-setup.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-mcp-setup/SKILL.md) The PlungeAI MCP server turns the whole platform into a control plane for any MCP client: discover and run agents, execute and build CNL workflows, run typed tool calls, bounded autonomous missions, schedules, persistent chat, human-in-the-loop approvals, and long-term memory. Everything it creates uses the same storage as Ocean Studio, so workflows, executions, and conversations cross-appear in every app and door. ## Prerequisites Self-service `ozk_` key: **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`) → create → copy it once. Ask the account owner only for a shared/team key minted under someone else's account. ## Connect Endpoint `https://mcp.plungeai.com/v1` (Streamable HTTP), auth header `Authorization: Bearer ozk_YOUR_KEY` (or `X-API-Key: ozk_YOUR_KEY`). `POST https://api.plungeai.com/v1/mcp` is the identical server on the API host, for a client that can only reach one host. One-click install page: `https://mcp.plungeai.com/install` (machine form: `/install.json`) — type the key into the box **before** clicking a button, so the deeplink is rewritten with the Authorization header baked in; clicked without a key the server installs auth-less and you add the header by hand afterward. **Generic client config** (any MCP client not covered by a `plungeai-in-<tool>` skill): 1. **Native remote/HTTP support (preferred):** URL `https://mcp.plungeai.com/v1`, header `Authorization: Bearer ozk_YOUR_KEY`. 2. **stdio-only client:** bridge with [mcp-remote](https://www.npmjs.com/package/mcp-remote) (Node 18+): ```json { "mcpServers": { "plungeai": { "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.plungeai.com/v1", "--header", "Authorization: Bearer ozk_YOUR_KEY"] } } } ``` Clients that mangle spaces inside `args` (mcp-remote's README names Cursor, Codex CLI, and Claude Desktop on Windows): pass `"--header", "Authorization:${AUTH_HEADER}"` plus `"env": { "AUTH_HEADER": "Bearer ozk_YOUR_KEY" }` in the same entry. The bridge is an `npx` process — a cold start can exceed a client's default startup timeout (Codex default: 10s); raise it where the client has one. 3. Neither → skip MCP and use the One API instead (`plungeai-api-setup`) — every capability is reachable over plain HTTPS. **Key handling.** User-level config, never committed: the literal key lives only in the tool's home config or its secret store, never in a repo file. A project-level config may only reference an env var. Before the first commit in any repo you just configured: ```bash git grep -n "ozk_" # tracked files grep -rn "ozk_" . --exclude-dir=.git --exclude-dir=node_modules # untracked too ``` Both must print nothing. ## Verify ``` plungeai_whoami {user_request: "verify my plungeai connection"} ``` Expect: user id, auth type + tier, key label, rate-limit window (used/minute, used/day), and the server identity (`mcp.plungeai.com`). A 401 means the key is missing/invalid — fix the header, don't retry blind. There is no permissions field on the card — fencing shows up as which tools `tools/list` returns, not on `whoami`. One real call proves the catalog too: `plungeai_list_agents {search: "web search"}` → live results. ## The five rules that prevent most failures 1. **Discovery first, ids never from memory.** The agent catalog is live and active-only. `plungeai_list_agents {search: "<capability in plain words>"}` is a hybrid semantic+keyword search — take agent ids verbatim from its results. An unknown or non-active id is REFUSED at execution (nothing runs); re-discover, never guess or reuse an id from an earlier session. 2. **Relay results verbatim.** Every successful tool output is final, platform-rendered, user-ready markdown. Present it in full — do not re-write, shorten, or summarize unless asked. The parts addressed to you are the guidance tails: execution-id footers, poll hints, and ⏸ continuation blocks — act on those. 3. **Structured outcomes, never blind retries.** Execution tools answer with a status envelope (`ok | needs_input | needs_connection | needs_api_key | needs_approval | unavailable | error`), never a raw error. Follow the `remediation`; never retry the identical call. 4. **⏸ approval fences are the user's, not yours.** A run pausing with `⏸ AWAITING USER APPROVAL: <action> (cost)` or `⏸ AWAITING USER: <question>` must be relayed verbatim. Only after the user decides do you call `plungeai_continue` (`approve: true` ONLY for an explicit yes; `message: "<their words>"` for an answer, denial, or change of course). NEVER approve on your own. 5. **Pass `user_request` on every call** — the user's original ask, verbatim, before you translated it into arguments. Every tool accepts it; the platform uses it for routing and support diagnostics. **Terminology trap:** users call their saved workflows "agents" too. An unqualified "show me my agents" means their SAVED WORKFLOWS → `plungeai_list_workflows`, not the registry (`plungeai_list_agents`). ## Sync vs async, and continuation - **Sync (default on most tools):** streams progress, returns the finished result. Typical workflows finish in seconds (parallel RPC fan-out). - **Async (`mode: "async"`):** returns an `execution_id` immediately; the run continues server-side. Use it for anything that could exceed ~3 minutes (Claude Desktop hard-caps a tool call at ~4 minutes). Poll `plungeai_get_workflow_status`, fetch with `plungeai_get_result`. Ceiling: ~15-minute wall cap per attempt. `plungeai_run_mission`/`plungeai_learn` default to async; `plungeai_execute_agent` has no `mode` — always sync. - **⏸ Continuation:** the pause appears as a tail on the result, on `plungeai_get_result`, and in `plungeai_get_workflow_status.structuredContent.continuation`. Relay it verbatim → ask the user → `plungeai_continue {execution_id, approve: true}` (yes) or `{execution_id, message: "<their words>"}` (no/change). The execution id doubles as the conversation session id. ## Tool map The catalog is served live by `tools/list` (20 tools at last sync — `tools/list` is authoritative; a fenced key sees fewer). Full parameter-level detail for each lives in the capability skill named below. | Tool | One-line purpose | Capability skill | |---|---|---| | `plungeai_whoami` | The authenticated identity, tier, key label, rate window | this skill | | `plungeai_list_agents` | Search the live agent registry (semantic); fetch one full card | `plungeai-discovery` | | `plungeai_get_tool_contract` | Exact invocation contract for one agent: schema, operations, credential status | `plungeai-discovery` | | `plungeai_execute_agent` | Run one prompt-driven agent once | `plungeai-agents` | | `plungeai_execute_tool` | Run one structured tool-agent with typed `{agent_id, operation, params}` | `plungeai-tools-connectors` | | `plungeai_get_result` | Fetch a run's output by execution id; `task_id` reads a single step | `plungeai-results-traces` | | `plungeai_execute_workflow` | Run a saved workflow or ad-hoc CNL YAML; sync streams, async polls | `plungeai-workflows` | | `plungeai_get_workflow_status` | Poll a run: status, error, duration, `continuation` when paused | `plungeai-workflows` | | `plungeai_list_workflows` | The user's saved workflows | `plungeai-workflows` | | `plungeai_workflow` | Workflow CRUD + versioning | `plungeai-workflows` | | `plungeai_build_workflow` | Generate a workflow from a goal, or refine one | `plungeai-workflows` | | `plungeai_executions` | Execution history: list/get/output/conversation/delete | `plungeai-results-traces` | | `plungeai_chat` | Persistent chat with the platform assistant | `plungeai-results-traces` | | `plungeai_followup` | Ask a follow-up on a completed run | `plungeai-results-traces` | | `plungeai_continue` | Resume a paused run: answer a question or deliver approval | this skill (above) | | `plungeai_run_mission` | Bounded autonomous agent mission (tool fence, iteration cap) | `plungeai-missions` | | `plungeai_learn` | Distill a URL/text/session into a reusable private skill | `plungeai-memory` | | `plungeai_schedule` | Cron jobs: stats/list/get/create/update/pause/resume/delete/run_now/runs | `plungeai-scheduling` | | `plungeai_memory` | Long-term memory: recall/remember/search_runs/get_run | `plungeai-memory` | | `plungeai_templates` | Workflow templates: list/get/use | `plungeai-workflows` | **Beyond tools**, the server also serves 8 MCP resources (registry or the caller's own data, ownership-checked): `plungeai://agents/list`, `/agents/categories`, `/agents/{category}`, `/personas/list`, `/workflows/list`, `/workflows/{id}`, `/executions/{id}`, `/docs/workflow-authoring` — plus one prompt, `/plungeai`, that primes a client with the platform operating instructions. ## Auth model, outcome envelope, trust fences **An API key IS a user identity** — the key resolves to a user id, and every read/write on every tool is scoped to what that user owns, the same view they have in Studio. A foreign id answers "not found," not "forbidden." Execution tools never return a raw error: the answer is text plus `structuredContent` with `status: ok | needs_input | needs_connection | needs_api_key | needs_approval | unavailable | error`, `summary`, and typed `remediation.actions` (`connect_provider`, `provide_api_key`, `provide_field`, `approve_via`/`respond_via`, `retry_with`, `use_alternative`). `isError` is true ONLY for terminal `error` outcomes — every other status is guidance, not a crash. Trust fences (surface, never retry, never bypass): the **active-only fence** refuses an unknown/inactive agent id before dispatch — re-discover, never retry the same id. The **approval fence** (`needs_approval` / ⏸) is a deliberate human boundary — only the user decides. **Connection fences** (`needs_connection`/`needs_api_key`) need the user's browser (Studio → Connectors) — relay instructions, wait, then retry the identical call once they confirm (the one case where repeating the same call is correct). Full protocol-error table, rate limits (free 30/min·1k/day, pro 100/min·10k/day, enterprise 300/min·100k/day), per-key fences (`allowed_ips`, `allowed_tools`), and the failure-classification table: [`references/identity-and-errors.md`](/skills/plungeai-mcp-setup/references/identity-and-errors). ## Troubleshooting | Symptom | Cause → fix | |---|---| | 401 (`Bearer ozk_ key required`) | Key typo'd, pasted with whitespace, or header never sent → fix the header in the client's config | | Connected, no `plungeai_*` tools — or fewer than expected | Client not reloaded after the config edit, or the key is fenced to a subset (`allowed_tools`): policy, not a bug | | 405 or an immediate connect error | Client is SSE-only or stdio-only (`GET /mcp` answers 405 at once) → use the mcp-remote bridge | | Bridge "never appears" / times out | npx cold start exceeded the client's startup timeout, or Node.js is missing | | 401 only through the bridge | Client mangled the spaces in `--header` → use `Authorization:${AUTH_HEADER}` + `env` (above) | | Works for one teammate, not another | Separate keys, separate fences — per-machine config | | 403 `refused` / 409 `approval_required` | Trust fence, not a connection problem — relay to the user | Per-tool reload steps and config paths (Cursor, VS Code, Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, Windsurf, Replit, Lovable, Bolt, v0): `plungeai-in-<tool>`. ## References - Full guide: https://mcp.plungeai.com/docs#1-quickstart — every tool's parameters and a `tools/call` example at https://mcp.plungeai.com/docs#14-tool-reference. - [`references/identity-and-errors.md`](/skills/plungeai-mcp-setup/references/identity-and-errors) — `plungeai_whoami` in full, the auth model, the two error planes (protocol vs tool-outcome), rate limits, per-key fences, and the failure classification table. ## Related skills - `plungeai-in-<tool>` — exact per-editor connect steps and quirks. - `plungeai-api-setup` — the same platform over REST instead of MCP. - `plungeai-cli-setup` — operate PlungeAI from a terminal. - `plungeai-workflows` — CNL YAML authoring deep-dive. - `plungeai-discovery`, `plungeai-agents`, `plungeai-tools-connectors`, `plungeai-missions`, `plungeai-scheduling`, `plungeai-memory`, `plungeai-results-traces` — per-tool capability detail. ## Reference pages <CardGroup cols={2}> <Card title="Identity & errors — whoami, the auth model, outcome envelope, trust fences" icon="file-text" href="/skills/plungeai-mcp-setup/references/identity-and-errors"> --- </Card> </CardGroup> # Identity & errors — whoami, the auth model, outcome envelope, trust fences Source: https://docs-preview.plungeai.com/skills/plungeai-mcp-setup/references/identity-and-errors <!-- sources-of-truth: orchestration/mcp-gateway/tools.ts, orchestration/mcp-gateway/README.md, orchestration/mcp-gateway/extras.ts, orchestration/mcp-gateway/auth-middleware.ts, orchestration/mcp-gateway/index.ts, orchestration/mcp-gateway/tool-outcome.ts, orchestration/mcp-gateway/server.ts | last-synced: 2026-09-24 (re-verified: auth order + unsupported_bearer_token against auth-middleware.ts, 20-tool catalog against server.ts TOOL_DEFS, rate limits against errors doc — all match; fixed a stale "Dashboard → API Keys" UI label to Dashboard → One API → Keys per apps/ocean-dashboard/src/nav.ts) --> --- ## plungeai_whoami **Purpose:** show the authenticated identity — the ground truth for "who am I acting as" and "how much budget is left". Read-only, no arguments beyond `user_request`. Use it to verify a new connection, and whenever ownership ("Execution not found") or rate-limit errors appear. **Example:** `{"user_request": "verify my plungeai connection"}` **Returns** ``` # Who am I - **User:** `<uuid>` - **Auth:** api-key · tier **pro** - **Key:** <label> (`<key id>`) - **Rate window:** N/min used · M/day used - **Server:** plungeai.com (mcp.plungeai.com) ``` **Failures & fixes:** "Authentication required." → the key never reached the server; fix the header (`Authorization: Bearer ozk_YOUR_KEY` or `X-API-Key: ozk_YOUR_KEY`). The rate window line is best-effort and may be absent — that alone is not an error. --- ## The auth model **An API key IS a user identity.** The key resolves to a user id, and every read/write on every tool is scoped to what that user owns — the same view that user has in Studio, never the whole system. Every id-based operation (executions, workflows, jobs, conversations, memory) is ownership-checked before any storage is read; a foreign id answers "not found", not "forbidden" — so a plausible-looking id that returns "Execution not found" usually belongs to someone else or is mistyped. Auth order: an internal service path an API key can never reach → `X-API-Key` → `Authorization: Bearer` (personal API keys, e.g. `ozk_YOUR_KEY`; any other bearer value is rejected — logged as `unsupported_bearer_token` — only `ozk_` keys authenticate, there is no OAuth token path today). Unauthenticated requests get **401** with a `WWW-Authenticate: Bearer` challenge (`error="invalid_token"` when credentials were supplied but invalid). Keys are self-service — mint your own at **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`); an account owner can additionally fence (`allowed_ips`/`allowed_tools`) or revoke any key on the account, including a shared team key. **Per-key fences** (both optional, set at mint): - `allowed_ips` — the key only authenticates from listed addresses/CIDRs; anywhere else is a 401 (and counts against failed-auth metering). - `allowed_tools` — other tools are HIDDEN from `tools/list`, and calling one returns `-32602 Tool not permitted for this key`. If a documented tool is missing from `tools/list`, the key is fenced — re-mint or edit the key's fence in the Dashboard; do not keep calling it. **Rate limits** are per tier: free 30/min · 1k/day, pro 100/min · 10k/day, enterprise 300/min · 100k/day (tool calls only). Over-limit → HTTP 429 with a `Retry-After` header — wait that long, then resume; never tight-loop. **Activity trail:** every request is recorded to a per-user daily log (arguments in full, answers as receipts). A user reads their own with their own key: `https://mcp.plungeai.com/log?date=YYYY-MM-DD` (Bearer header, or `&key=ozk_YOUR_KEY` in a browser). This is also why `user_request` matters: it is the one place the user's actual sentence survives into diagnostics. --- ## Two error planes **1. Protocol errors (JSON-RPC, transport-level)** — the request itself was rejected; no tool ran: | Signal | Meaning | Your move | |---|---|---| | 401 + `WWW-Authenticate` | Missing/invalid/revoked key, or IP outside the key's fence | Fix the credential; don't retry blind. Repeated failures meter the IP (429 with Retry-After). | | 429 + `Retry-After` | Rate limit (per-tier), or failed-auth metering | Wait the stated seconds, resume, consider batching. | | `-32602` "Tool not found" / "Tool not permitted for this key" | Typo'd tool name, or a key fence | Re-check against `tools/list`; if fenced, edit the key's fence in the Dashboard. | | `-32700` Parse error / 413 body too large (1 MiB) | Malformed or oversized request | Fix the payload; huge YAML belongs in a saved workflow, not inline. | | 405 / 403 invalid Host / `-32603` internal | Transport misuse or server fault | Use POST to the canonical endpoint; internal errors: retry once, then report. | One deliberate crossover: arguments that fail a tool's own schema (e.g. `limit: 200`) are pre-screened BEFORE the tool runs and still answer in the envelope — `needs_input`, "`<tool>` was not called — its arguments do not match the tool's schema", with `provide_field` actions per bad field. Nothing ran; fix the named fields against the tool's `inputSchema` from `tools/list`. **2. Tool outcomes (the envelope)** — the tool ran (or deliberately refused) and answered with structured guidance. Execution tools NEVER return a raw error: the answer is text plus `structuredContent` with ``` status: ok | needs_input | needs_connection | needs_api_key | needs_approval | unavailable | error summary, agent_id?, operation?, result?, execution_id?, missing?[], warnings?[], contract?, remediation: { message, actions: [...] } ``` Typed `remediation.actions` tell you the exact next move: `connect_provider` (user opens the named URL and connects — needs their browser), `provide_api_key` (user saves a key in a PlungeAI app), `provide_field` (fix that field, retry the same call), `approve_via` / `respond_via` (the ⏸ loop → `plungeai_continue`), `retry_with` (retry with the stated changes, e.g. `{mode: "async"}`), `use_alternative` (a real, callable substitute agent id). `isError` is true ONLY for terminal `error` outcomes. Every other non-ok status is guidance the model acts on — the response even ends with "This is structured guidance, not a crash — do not retry the identical call." Believe it. --- ## The trust fences (surface, never retry, never bypass) **The active-only fence.** Only `status:active` agents are listed and callable over MCP. `plungeai_execute_agent`, `plungeai_execute_tool`, ad-hoc YAML in `plungeai_execute_workflow` (including agents nested in `parallel`/`sequential` blocks), and `plungeai_schedule` create all refuse an unknown or inactive id BEFORE dispatch, writing no execution row. Every refusal's prose points you at `plungeai_list_agents`; `plungeai_execute_agent` and `plungeai_execute_tool` additionally attach live `use_alternative` suggestions to their `unavailable` envelope — `plungeai_execute_workflow`'s fence refusal carries no remediation actions, and `plungeai_schedule` create answers with plain error text, not an envelope. A refusal is a policy answer, not a transient failure: **always re-discover** with `plungeai_list_agents` (semantic `search`), take a fresh id from the results, and never "retry" the refused id or guess a variant spelling. **The approval fence.** Gated operations and real-world side effects pause as `needs_approval` / `⏸ AWAITING USER APPROVAL` (a paused run also shows it in `plungeai_get_workflow_status` → `continuation`). This is a deliberate trust boundary between the platform and the human: relay it verbatim, let the USER decide, and only then `plungeai_continue {approve: true}` (yes) or `{message: "<their words>"}` (no / change). Approving on your own, retrying around the pause, or resubmitting the original call are all violations — the platform holds the pending action server-side until the user answers. **Connection fences.** `needs_connection` / `needs_api_key` mean the USER must act in their browser (connect an account or save a key in a PlungeAI app, e.g. Studio → Connectors, per the remediation's URL). Relay the exact instructions, wait for their confirmation, then retry the IDENTICAL call — this is the one case where the same call is expected to be repeated, and only after the user acted. **Ownership answers.** "not found / not one of your executions" on a plausible id is an ownership verdict, not a storage glitch — re-list (`plungeai_executions`, `plungeai_list_workflows`, `plungeai_schedule {action: "list"}`) and use an id the account actually owns. --- ## Failure classification you can rely on Whatever the pre-flight didn't predict, the engine's raw failure is classified into the same envelope — a named missing API key becomes `needs_api_key`, an upstream 401 becomes `needs_connection` naming the provider to connect, insufficient OAuth scopes become "reconnect to grant additional scopes", missing/invalid inputs become `needs_input` WITH the agent's contract attached, an undeployed binding becomes `unavailable` with alternatives, and a timeout becomes `error` with `retry_with {mode: "async"}`. A failed run always carries a reason — `plungeai_get_result` on a failed id answers "This run failed: <reason>" rather than a dead end. So: read the status, follow the remediation, and reserve blind one-time retries for the one class labeled transient ("This is a transient platform failure ... Retry once in a few seconds", stamped with a request id to report if it persists). # plungeai-agents Source: https://docs-preview.plungeai.com/skills/plungeai-agents Run a PlungeAI registry agent: recognize the two kinds (prompt-driven vs structured tool-agents), execute a prompt-driven one sync or async (`plungeai_execute_agent` MCP / `POST /v1/agents/{id}/execute` REST, incl. streaming SSE), and redeem results by execution id (`plungeai_get_result` / `GET /v1/agents/results/{workflowId}/{taskId}`). Use when running a single building-block agent (search, LLM, documents, finance, CRM, …), choosing the right execution door for an agent card, polling/redeeming an async run, or fixing a `missing_prompt`/`unknown_agent`/`unknown_model` error. For finding an agent id use `plungeai-discovery`; for structured tool-agents with typed params/operations use `plungeai-tools-connectors`; for chaining several agents use `plungeai-workflows`; for model/provider detail use `plungeai-models`. [Download zip](https://skills.plungeai.com/plungeai-agents.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-agents/SKILL.md) An **agent** is a deployed capability with a uniform interface: it accepts a task, does one job well, and stores its result where the platform can hand it to the next step. Agents are the building blocks workflows chain, missions call, and tools are a structured sub-species of. The catalog is **live and active-only** — execution refuses any id that isn't currently active. ## Prerequisites - Self-service `ozk_` key from **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`). - MCP: `https://mcp.plungeai.com/v1`. REST: `https://api.plungeai.com`. ## Discovery first Never call an agent id from memory. `plungeai_list_agents {search: "<capability in plain words>"}` (MCP) or `GET /v1/discovery/search?kind=agents&q=…` (REST) — full mechanics in `plungeai-discovery`. Fetch the full card (`plungeai_list_agents {agent_id}` / `GET /v1/discovery/cards/agent/{id}`) before first use of an unfamiliar agent — it tells you which of the two kinds below you have, and carries "Not for → use X instead" redirects. ## Two kinds — pick the right execution door | Kind | How you recognize it | How to execute | |---|---|---| | **Prompt-driven** | Card describes free-text input (`llm-agent`, `skill-agent`, search agents like `brave-agent`, `exa-agent`) | This skill: `plungeai_execute_agent` / `POST /v1/agents/{id}/execute` with a `prompt` | | **Structured tool-agent** | Card carries a **Parameters table** / operations (document converters, weather, data-table, calendar, payments) | `plungeai-tools-connectors`: fetch the contract, then typed `params` | Sending prose to a structured agent (or typed fields to a prompt-driven one) is the most common execution mistake — the card tells you which you have. ## Execute — MCP ```json plungeai_execute_agent { agent: "llm-agent", prompt: "Summarize the three biggest risks in this text: ..." } ``` Always sync (no `mode` param); `session_id` continues a conversational session; `persona`/`model`/`provider`/`maxTokens`/`temperature`/`top_p`/ `reasoning_effort`/`thinking_level`/`streaming` override per call. Full parameter table, failures, and `plungeai_get_result` — [`references/mcp-execute-and-result.md`](/skills/plungeai-agents/references/mcp-execute-and-result). ## Execute — REST ```bash curl -s -X POST https://api.plungeai.com/v1/agents/llm-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{"prompt": "One-paragraph brief: the current state of solid-state batteries", "model": "claude-sonnet-5", "maxTokens": 2048}' ``` `sync: false` → 202 pointer, redeemed at `GET /v1/agents/results/{workflowId}/{taskId}` (poll on `404 not_ready`). `stream: true` → an OpenAI-shaped `chat.completion.chunk` SSE instead of a JSON body. Full field list, streaming shape, error catalogue, and the polling pattern — [`references/rest-agents-plane.md`](/skills/plungeai-agents/references/rest-agents-plane). ## Redeem a result later ```json plungeai_get_result {execution_id: "<id from the run's footer>"} ``` Every execution — even a single agent call — hands back a `workflow_id`/`task_id` (or `execution_id`) pair you can redeem later, or read one step's output with `task_id`. ## Gotchas - **"Show me my agents" ≠ the registry.** Users mean their saved workflows (`plungeai_list_workflows`); `plungeai_list_agents` is the platform's own building-block catalog, for when YOU are composing. - **`plungeai_execute_agent` has no async mode.** For a long single-agent run, use the One API with `sync: false`, or wrap it in a one-task workflow via `plungeai_execute_workflow {mode: "async"}` (`plungeai-workflows`). - **Unknown `model` fails BEFORE the run starts** (`needs_input` / `422 unknown_model`), with near-match suggestions — never a silent bad default. - **Idempotency.** Payment-, messaging-, and automation-class agents may duplicate side effects on re-runs. Check execution status before re-firing a call that may already have acted. - **A `502 result_unavailable` on a sync call isn't always a failure** — the result may land late; its error body still carries `workflow_id`/`task_id` to redeem with. ## Related skills - `plungeai-discovery` — search, full cards, tool contracts, templates. - `plungeai-tools-connectors` — structured tool-agents, typed params, connected-account status. - `plungeai-models` — provider factory (`model`/`provider` fields) and the money plane for your own code. - `plungeai-workflows` — chain several agents; async execution surface for long single-agent runs. - `plungeai-results-traces` — tracing a run end-to-end, execution history, cost. ## Reference pages <CardGroup cols={2}> <Card title="Executing agents over MCP — execute_agent, get_result" icon="file-text" href="/skills/plungeai-agents/references/mcp-execute-and-result"> Two execution styles, chosen by the agent's card: </Card> <Card title="Agents — the registry, discovery, and execution" icon="file-text" href="/skills/plungeai-agents/references/registry"> An agent is a deployed capability with a uniform interface: it accepts a task, does one job well (search the web, call an LLM, convert a document, post to… </Card> <Card title="Agents plane — /v1/agents" icon="file-text" href="/skills/plungeai-agents/references/rest-agents-plane"> Execute any active platform agent with a plain prompt. </Card> </CardGroup> # Executing agents over MCP — execute_agent, get_result Source: https://docs-preview.plungeai.com/skills/plungeai-agents/references/mcp-execute-and-result <!-- sources-of-truth: orchestration/mcp-gateway/tools.ts, orchestration/mcp-gateway/server.ts, orchestration/mcp-gateway/tool-exec.ts, orchestration/mcp-gateway/registry-cards.ts, orchestration/mcp-gateway/tool-outcome.ts | last-synced: 2026-09-24 (execute_agent/get_result half of the original discovery-and-execution.md; the list_agents/get_tool_contract half lives in plungeai-discovery, the execute_tool half lives in plungeai-tools-connectors. Re-verified: ExecuteAgentSchema field-by-field, promptText max 65536, against tools.ts — all match, no drift found) --> Two execution styles, chosen by the agent's card: - **Prompt-driven agents** (a prose brief does the work — research, writing, LLM tasks) → `plungeai_execute_agent`. - **Structured tool-agents** (cards with a Parameters table — posting, document conversion, weather, payments) take typed fields, not prose → `plungeai_get_tool_contract` then `plungeai_execute_tool` (see `plungeai-tools-connectors`). When unsure, fetch the card (`plungeai_list_agents {agent_id}`, see `plungeai-discovery`) — a Parameters table means structured. --- ## plungeai_execute_agent **Purpose:** run a single PROMPT-DRIVEN agent once. Pre-built agent cards (capability packs rather than deployed services) are lowered automatically to a harness run — same call shape either way. Always sync (no `mode` param). **Parameters** | Param | Type | Notes | |---|---|---| | `agent` | string, required | Agent id from a live `plungeai_list_agents` search. | | `prompt` | string ≤65536, required | The brief. | | `persona` | string | Persona id to inject. | | `model` | string | Model override — must exist in the platform model catalog (see failure below). Omit to use the agent's default. | | `provider` | string | Provider id override (`anthropic`, `openai`, `gemini`, …) — pairs with a pinned `model`. | | `maxTokens` | int 1–64000 | Output cap. | | `max_tokens` | int 1–64000 | Same as `maxTokens` — the One API / snake_case spelling. | | `temperature` | number 0–2 | Sampling temperature. | | `top_p` | number 0–1 | Nucleus sampling. | | `reasoning_effort` | `low` \| `medium` \| `high` \| `xhigh` | Reasoning budget on models that expose one. | | `thinking_level` | string | Provider thinking-level id (Gemini-style), forwarded to the task as-is. | | `streaming` | boolean | Default on — the engine streams the run internally so the answer lands the moment the model finishes; `false` switches that off. No token stream reaches an MCP client either way (results are one envelope). | | `session_id` | string | Start/continue a conversational agent session — reuse the same id across turns. | | `format` | `markdown` \| `json` | Response serialization; default markdown. | **Example** ```json {"user_request": "summarize this week's AI safety news", "agent": "llm-agent", "prompt": "Summarize the most important AI safety developments this week, with sources."} ``` **Returns:** an outcome envelope. `ok` → the agent's final markdown + execution-id footer. A conversational agent that stops mid-dialog returns `needs_approval` / `needs_input` with a ⏸ block → relay and use `plungeai_continue`. **Failures & fixes** - Unknown agent id → `unavailable`: "No such agent ... ids cannot be guessed" + live alternatives. Re-discover; never retry the same id. - Inactive agent id → `unavailable`: "not `status:active`". Pick an alternative from the remediation or a fresh search. - Unknown `model` → `needs_input` BEFORE anything runs, with near-match catalog models. Omit `model` or pick a suggested catalog id. (The preflight exists because a bogus model would otherwise time out minutes later with no cause.) - Structured tool-agent called with prose → may run its default operation or reject inputs; switch to the contract + `plungeai_execute_tool`. --- ## plungeai_get_result **Purpose:** retrieve the output of one of the caller's executions by execution id — the id from any run's footer, from `plungeai_executions`, or from `plungeai_schedule {action: "runs"}`. Read-only, ownership-checked. **Parameters** | Param | Type | Notes | |---|---|---| | `execution_id` | string | **Preferred** id param (matches `run_mission`/`get_workflow_status`/`continue` output). | | `workflow_id` | string | Back-compat alias for `execution_id`. Engine ids (`exec-...`, hyphen) also resolve. | | `task_id` | string | Read one step's output instead of the final result. Step ids come from the result's own "Steps in this run" index. | | `format` | `markdown` \| `json` | Response serialization; default markdown. | Exactly one of `execution_id`/`workflow_id` is required (enforced at call time, not by the schema — both stay optional in the advertised tool signature). **Example** ```json {"user_request": "show me the full result of that run", "execution_id": "d3adb33f-...."} ``` **Returns (full result):** an identity header (workflow name — the question — timestamp — execution id), the final output verbatim, then as applicable: a **Steps in this run** index (multi-task runs persist only the final task's output; every other step is readable via `task_id`), the full **Conversation thread** (all follow-up turns, Studio-parity), and a ⏸ continuation block if the run is paused. Show it to the user whole. **Failures & fixes** - "No result found for <id>, or it is not one of your executions." → wrong or foreign id; take the id from the run's own footer or `plungeai_executions {action: "list"}`. - "still running. Poll plungeai_get_workflow_status, then retry." → do that; don't hammer get_result. - "This run failed: <reason>" → surface the reason; fix per its content (often a `needs_*` classification on the original call). - "completed, but its stored result is no longer retrievable (expired from SharedMemory)" → step outputs and old results expire; only the final result blob is durable. Re-run if the user needs it again. - Scheduler run ids (`exec_...`, underscore) never resolve here → use `plungeai_schedule {action: "runs"}` and take its **Execution ID** column (see `plungeai-scheduling`). --- ## Putting it together — the canonical single-agent run ``` 1. plungeai_list_agents {search: "summarize a pdf"} → llm-agent (or a domain agent) 2. plungeai_execute_agent {agent: "llm-agent", prompt: "Summarize the attached brief in three bullets."} → ok, final markdown + execution id 3. plungeai_get_result {execution_id: "<id>"} → re-fetch the same output later, or a step's output by task_id ``` For long-running prompt-driven work, wrap it in a one-task workflow via `plungeai_execute_workflow {mode: "async"}` (`plungeai-workflows`) — a bare `plungeai_execute_agent` call has no async mode. # Agents — the registry, discovery, and execution Source: https://docs-preview.plungeai.com/skills/plungeai-agents/references/registry <!-- sources-of-truth: docs/architecture.md, orchestration/CLAUDE.md (registry), orchestration/mcp-gateway/server.ts, orchestration/api-gateway/openapi.ts, docs/PLUNGE-AI-AGENTS.md | last-synced: 2026-09-24 (re-verified: ~10-20ms RPC overhead claim against docs/architecture.md, GET /v1/agents and /v1/agents/categories shapes against routes/agents.ts — all match, no drift found) --> An **agent** is a deployed capability with a uniform interface: it accepts a task, does one job well (search the web, call an LLM, convert a document, post to Slack, enrich a CRM contact), and stores its result where the platform can hand it to the next step. Agents are the building blocks everything else composes: workflows chain them, missions call them, tools are a structured sub-species of them. The catalog is **live and active-only**: every listed agent is deployed and callable, and execution refuses any id that is not currently active. That is why ids must come from a live lookup, never from memory or an example you saw yesterday. ## Two kinds of agent — pick the right execution door | Kind | How you recognize it | How to execute | |---|---|---| | **Prompt-driven** | Card describes free-text input (e.g. `llm-agent`, `skill-agent`, search agents like `brave-agent`, `exa-agent`) | `plungeai_execute_agent` (MCP) or `POST /v1/agents/{id}/execute` (One API) with a `prompt` | | **Structured tool-agent** | Card carries a **Parameters table** / operations (e.g. document converters, weather, data-table, calendar agents) | Fetch the contract first (`plungeai_get_tool_contract` / `GET /v1/tools/{id}`), then `plungeai_execute_tool` / `POST /v1/tools/{id}/execute` with typed `params` — see the `plungeai-tools-connectors` skill | Sending prose to a structured agent, or typed fields to a prompt-driven one, is the most common execution mistake. The agent card tells you which kind you have. ## Terminology trap: "my agents" Users call their **saved workflows** "agents" too. An unqualified "show me my agents" means their saved workflows → `plungeai_list_workflows`. The registry (`plungeai_list_agents`) is the platform capability catalog — building blocks like `exa-agent` — and is what YOU use when selecting components. Only use the registry listing when the user explicitly asks about platform capabilities, or when you are composing. ## Discovery ### MCP: `plungeai_list_agents` `search` is a **hybrid semantic + keyword** query over live agent cards. Describe the capability in natural language and trust the ranking: ``` plungeai_list_agents {search: "convert pdf to markdown"} plungeai_list_agents {search: "web search"} plungeai_list_agents {category: "financial"} plungeai_list_agents {agent_id: "exa-agent"} # full card for one agent ``` - Prefer `search`/`category` filters. An unfiltered listing returns the whole catalog (large, slow to read, rarely what you want — discover, don't page through). - Fetch the **full card** (`agent_id`) before first use of an unfamiliar agent. Cards carry: operations, parameters, good-at examples, and — critically — **"Not for → use X instead"** redirects that save you a wrong pick. ### One API ```bash # List active agents (paged) curl -s "https://api.plungeai.com/v1/agents?limit=20&offset=0" \ -H "Authorization: Bearer ozk_YOUR_KEY" # Hybrid search over the whole registry (agents, mcp-servers, …) curl -s "https://api.plungeai.com/v1/discovery/search?q=web%20search&kind=agents&fields=summary" \ -H "Authorization: Bearer ozk_YOUR_KEY" # Ask the platform to recommend the best card for a task curl -s -X POST https://api.plungeai.com/v1/discovery/recommend \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{"type": "agent", "task": "find recent news about a company"}' # Full card, markdown LLM view curl -s https://api.plungeai.com/v1/discovery/cards/agent/exa-agent \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` Search response envelope: `{cards: [...], count, searchMethod}`. Each card carries `id, name, type, category, status, description, tags`. Add `include=quality` to get a `quality` block per card (`score`, `success_rate`, `runs` — `null` when unmeasured); use it to prefer proven agents when several match. `mode=hybrid|keyword|vector` forces a search leg; the default hybrid is almost always right — do not re-implement ranking client-side. ## Categories (orientation, not an inventory) Agents are organized by domain: **search** (Brave, Tavily, Exa, Perplexity, Serper), **generic LLM** (llm-agent, skill-agent), **documents**, **financial**, **CRM** (large family: enrichment, outreach, scoring), **coding**, **legal**, **healthcare**, **logistics**, **marketing**, **market research**, **social**, **payments**, **e-commerce**, **news**, **travel**, **design**, **automation**, **Google Workspace** (gmail, calendar, drive), **Microsoft 365**, and more. Category names are stable; membership is not — discover live. Stable id shape: kebab-case, usually `<thing>-agent` (`brave-agent`, `exa-agent`, `llm-agent`). Beware near-misses: `brave-agent` exists, `brave-search` may not — take the id character-for-character from the search result. ## Execution ### MCP: `plungeai_execute_agent` ``` plungeai_execute_agent { agent: "llm-agent", prompt: "Summarize the three biggest risks in this text: ...", session_id: "optional — start/continue a conversational session" } ``` - The id parameter is **`agent`** (not `agent_id`, which belongs to the tool-contract door). Optional per-call overrides: `persona`, `model`, `maxTokens`. - Returns a structured outcome. `ok` → the result content (final, user-ready markdown — relay verbatim). Anything else names the remediation (see SKILL.md "Trust fences"). - `session_id` makes conversational agents stateful across calls. - **This tool has no `mode` parameter — it is always sync.** For a long single-agent run, use the One API with `"sync": false` (below), or run it as a one-task workflow via `plungeai_execute_workflow {mode: "async"}` → poll `plungeai_get_workflow_status`, fetch with `plungeai_get_result`. ### One API: `POST /v1/agents/{id}/execute` ```bash curl -s -X POST https://api.plungeai.com/v1/agents/llm-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{ "prompt": "One-paragraph brief: the current state of solid-state batteries", "model": "claude-sonnet-5", "maxTokens": 2048, "sync": true }' ``` Sync response (default): ```json { "content": "…final markdown…", "workflow_id": "exec-…", "task_id": "…", "request_id": "…" } ``` `input` is an alias for `prompt`; `persona` injects a persona (see the `plungeai-skills-plugins` skill); `model`/`maxTokens` override per call. **Async:** `"sync": false` → `202` with `{workflow_id, task_id, request_id}`. Redeem: ```bash curl -s https://api.plungeai.com/v1/agents/results/{workflowId}/{taskId} \ -H "Authorization: Bearer ozk_YOUR_KEY" # 200 {content, content_type, workflow_id, task_id} | 404 {error: {code: "not_ready"}} ``` `404 not_ready` means still running — poll again; it is not a failure. ### Errors you will actually see | Signal | Meaning | Do | |---|---|---| | `400 missing_prompt` | No prompt/input in body | Send one | | refusal naming the agent as parked/unknown | Id not active in the live catalog | Re-search the registry; take a live id | | `502 engine_error` / `result_unavailable` | Downstream execution failed | Read the message; check traces (`plungeai-results-traces`); do not hammer-retry | | Outcome `needs_connection` | Agent needs a user credential (e.g. Google OAuth) | Tell the user what to connect in Studio, then retry | ## Under the hood (why it behaves this way) Every agent implements the same interface — `executeTask(yaml) → string` over Cloudflare service-binding RPC — which is what makes agents interchangeable inside workflows and lets the engine fan them out in parallel with ~10-20 ms dispatch overhead. Results are written to SharedMemory keyed by `(workflow_id, task_id, your user id)`, which is why every execution — even a single agent call — hands back a `workflow_id`/`task_id` pair you can redeem later. See the `plungeai-memory` skill for retrieval and `plungeai-workflows` for composition. ## Checklist before any agent call 1. Id from a live search (never memory). 2. Full card read if unfamiliar — right kind (prompt vs structured), right agent ("Not for" redirects honored). 3. Right door: prompt-driven → execute_agent; structured → contract + execute_tool. 4. Long run → async mode. 5. Outcome remediation followed; fences surfaced, never retried blind. # Agents plane — /v1/agents Source: https://docs-preview.plungeai.com/skills/plungeai-agents/references/rest-agents-plane <!-- sources-of-truth: orchestration/api-gateway/openapi.ts, orchestration/api-gateway/routes/agents.ts, docs/ONE-API-DEVELOPER-GUIDE-2.0.md | last-synced: 2026-09-24 (re-verified error catalogue, 403 agent_not_active / 404 unknown_agent pre-dispatch fence, and outcomeStatus mapping against routes/agents.ts, lib/agent-fence.ts and routes/_util.ts — all match, no drift found) --> Execute any active platform agent with a plain prompt. The gateway wraps your call in a one-task workflow, so every execution yields a `workflow_id` + `task_id` pair — that pair is the handle for async redemption and for traces. Auth: `Authorization: Bearer ozk_YOUR_KEY` on every route here. ## GET /v1/agents — list active agents Query params: `limit` (default 50, max 100), `offset` (default 0). ```bash curl -s "https://api.plungeai.com/v1/agents?limit=2" \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "agents": [ { "id": "llm-agent", "name": "LLM Agent", "type": "agent", "category": "ai", "status": "active", "description": "General-purpose LLM completion agent", "tags": ["llm", "completion"] }, { "id": "brave-agent", "name": "Brave Search", "type": "agent", "category": "search", "status": "active", "description": "Web search via Brave", "tags": ["search", "web"] } ], "count": 2 } ``` Each entry is a registry `Card` (summary fields). `count` is the returned page's length, not the catalog total — page until a short page, never until `offset >= count`. A failed registry hop returns `502 upstream_error`. The catalog is live — take ids verbatim from this listing or from `GET /v1/discovery/search`; never from memory. For richer capability search (semantic, filtered, quality scores) use the discovery plane — see the `plungeai-discovery` skill. ## GET /v1/agents/categories — agent categories with counts Agent categories with active-agent counts, aggregated from the registry (the registry has no categories endpoint of its own). **Not** a cache-stats pass-through — an older version of this route proxied `/api/registry/stats` and returned cache statistics instead; that shape is gone. ```bash curl -s https://api.plungeai.com/v1/agents/categories \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "categories": [ { "name": "search", "count": 12 }, { "name": "documents", "count": 9 } ], "count": 2 } ``` `categories[]` is sorted by count descending, then name. `count` is the number of distinct categories, not the total agent count. The aggregation queries only the first 100 active agents from the registry (one page, `limit=100&offset=0`) — on a catalog past 100 active agents this is a representative sample of category names, not a guaranteed-complete count over every active agent. A failed registry hop returns `502 upstream_error`, same as `GET /v1/agents`. ## POST /v1/agents/{id}/execute — run an agent Body fields: | Field | Type | Notes | |---|---|---| | `prompt` | string | The instruction. **Required** (or `input`) | | `input` | string | Alias for `prompt` | | `persona` | string | Optional persona overlay | | `provider` | string | Provider id (`anthropic`, `openai`, `gemini`, …); required alongside a pinned `model` | | `model` | string | Optional model override for LLM-driven agents | | `maxTokens` | integer | Optional completion cap (`max_tokens` accepted as an alias — OpenAI habits work) | | `max_tokens` | integer | Alias for `maxTokens` | | `temperature` | number | Sampling temperature, forwarded to the provider | | `top_p` | number | Nucleus sampling probability, forwarded to the provider | | `reasoning_effort` | string | Reasoning-effort hint (e.g. `low`/`medium`/`high`) for reasoning models | | `thinking_level` | string | Extended-thinking level hint for models that support it | | `system` | string | System prompt / instructions for the run | | `messages` | array | Prior chat messages (`[{role, content}]`) instead of a single `prompt` | | `sync` | boolean | Default `true`. `false` → 202 pointer | | `stream` | boolean | Default `false`. `true` → an OpenAI-shaped `chat.completion.chunk` SSE instead of a JSON result (see "Streaming" below). Ignored on the async pointer path | | `format` | string | Response negotiation: `json` (default) \| `yaml` \| `markdown` \| `text` — same values as an `Accept` header (`application/json`, `text/yaml`, `text/markdown`, `text/plain`) or the request `Content-Type` mirror | ### Sync (default) — result inline ```bash curl -s -X POST https://api.plungeai.com/v1/agents/llm-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "Summarize in one line: Cloudflare Workers are serverless."}' ``` ```json { "content": "Cloudflare Workers run code at the edge without managing servers.", "workflow_id": "00000000-0000-4000-8000-000000000001", "task_id": "t1", "request_id": "00000000-0000-4000-8000-000000000004" } ``` ### Async — 202 + pointer Use for long-running prompts, or when your caller can't hold a connection. ```bash curl -s -X POST https://api.plungeai.com/v1/agents/llm-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "Write a 2000-word market analysis of edge computing", "sync": false}' ``` HTTP **202**: ```json { "workflow_id": "00000000-0000-4000-8000-000000000001", "task_id": "t1", "request_id": "00000000-0000-4000-8000-000000000004" } ``` ### Streaming (`stream: true`) Instead of a JSON result, the 200 response is `text/event-stream`: an OpenAI-shaped `chat.completion.chunk` per line — ``` data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1788574344,"model":"llm-agent","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]} data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1788574344,"model":"llm-agent","choices":[{"index":0,"delta":{"content":"391"},"finish_reason":null}]} data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1788574344,"model":"llm-agent","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: [DONE] ``` One primer chunk (`delta.role: "assistant"`), then a `delta.content` chunk per provider token, then a final chunk (`delta: {}`, `finish_reason: "stop"` or `"length"` when truncated at `max_tokens`), then a literal `data: [DONE]` line. `usage` is emitted on the final chunk only when the provider reports the prompt/completion split (often omitted for streamed runs). Comment keepalives (`: OCEAN PROCESSING`) may appear every ~15s while idle. Response header `X-Execution-Id` carries the execution id for result redemption / polling regardless of `stream`. An error before the first byte is a normal JSON error envelope (not SSE); an error after the first byte is a single `data: {"error":{…}}` frame and the stream closes WITHOUT `[DONE]`. ### Errors | Status | Code | Meaning | |---|---|---| | 400 | `missing_prompt` / `invalid_format` | No prompt/input given, or `format` isn't one of `json`/`yaml`/`markdown`/`text` | | 401 | `unauthorized` | Bad/missing `ozk_` key | | 403 | `agent_not_active` | The agent card is not `status:active` (refused pre-dispatch) | | 404 | `unknown_agent` | No such agent id in the registry (refused pre-dispatch) | | 409 | `duplicate_execution_id` | The `x-trace-id` header was already used by an earlier run — send a fresh UUID | | 413 | `payload_too_large` | Body over 1 MiB (`MAX_REQUEST_SIZE`) | | 422 | `invalid_params` / `unknown_model` / `empty_completion` | Missing/invalid input named by the agent; pinned model absent/inactive in the catalog; or the run completed but the model returned no visible content — raise `max_tokens` ≥ 64 or change the model | | 424 | `connection_required` / `credential_required` | The agent needs a connection or key the user hasn't set up | | 429 | `rate_limited` | `Retry-After` header | | 502 | `engine_error` / `result_unavailable` | Engine dispatch failed, or sync redemption couldn't fetch the stored result | | 502 | `upstream_error` | A downstream hop threw (catch-all, any route in this plane) | | 503 | `agent_unavailable` | Agent temporarily down | A `502 result_unavailable` on a sync call does NOT always mean the run failed — the result may land late, and its error body carries `workflow_id` + `task_id`. Redeem with those ids at the results route below before re-running. ## GET /v1/agents/results/{workflowId}/{taskId} — redeem an async result ```bash curl -s https://api.plungeai.com/v1/agents/results/00000000-0000-4000-8000-000000000005/t1 \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` Ready — HTTP 200 (`StoredResult`): ```json { "content": "# Edge Computing Market Analysis\n\n...", "content_type": "text/markdown", "workflow_id": "00000000-0000-4000-8000-000000000001", "task_id": "t1" } ``` Not ready yet — HTTP 404: ```json { "error": { "code": "not_ready", "message": "result not available (yet)" } } ``` Results are tenant-scoped: you can only redeem pointers created by your own key's identity. ### Polling pattern `404 not_ready` is the normal in-flight state. Poll with backoff, cap the wait: ```bash WF=00000000-0000-4000-8000-000000000005; TASK=t1 for i in 1 2 3 4 5 6 7 8; do sleep $((i * 2)) BODY=$(curl -s -w '\n%{http_code}' \ "https://api.plungeai.com/v1/agents/results/$WF/$TASK" \ -H "Authorization: Bearer ozk_YOUR_KEY") [ "$(echo "$BODY" | tail -1)" = "200" ] && { echo "$BODY" | sed '$d'; break; } done ``` ```python import time, requests def redeem(wf, task, key, tries=8): for i in range(1, tries + 1): r = requests.get( f"https://api.plungeai.com/v1/agents/results/{wf}/{task}", headers={"Authorization": f"Bearer {key}"}) if r.status_code == 200: return r.json()["content"] if r.status_code != 404: r.raise_for_status() time.sleep(2 * i) # backoff; 404 not_ready is normal raise TimeoutError("result not ready") ``` ## Choosing sync vs async - **sync (default)**: single quick task, interactive callers. Simplest code. - **async (`sync:false`)**: anything that may run long; queue workers; retries survive process restarts because the pointer is durable. - Send an `x-trace-id` header on the execute call and you can watch the run's spans at `GET /v1/traces/<your-trace-id>` while polling — see the `plungeai-results-traces` skill. # plungeai-campaigns Source: https://docs-preview.plungeai.com/skills/plungeai-campaigns Run a list to completion on PlungeAI: the campaign ledger (claim/complete/fail/retry over data-table-agent), the campaign-config block (list source, cycle, cadence, retries, delivery), and how a campaign keeps going via cron or self-scheduling runAgain. 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. There is no dedicated public API/MCP tool for this — author it in Studio with `plungeai-campaign-agent`, or as a plain workflow using the operations documented here; for the pipeline steps themselves use `plungeai-workflows`. [Download zip](https://skills.plungeai.com/plungeai-campaigns.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-campaigns/SKILL.md) 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) if you're calling the platform directly, or build the pipeline in Ocean Studio. - **This capability has a thin public surface, by design honesty:** neither `https://api.plungeai.com` nor `https://mcp.plungeai.com/v1` exposes a dedicated campaign-management route or MCP tool today. The supported path is Studio's **`plungeai-campaign-agent`** kind (CNL + a `campaign-config` block); everything below is real, source-grounded detail for reading, extending, or hand-building a campaign pipeline as an ordinary workflow. ## 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>"}`. `data-table-agent` itself is a registry agent id, confirmed the same way. ## The shape 1. **`campaignClaim`** — a `type: task` leases up to `batch_size` pending items for this run. 2. **`type: batch` with `ledger: 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 as `campaignComplete`/`campaignFail`. 3. **A `campaign-config` fenced block** after the YAML tells Studio the list source, cycle (`once`/`hourly`/`daily`/`weekly`/`monthly`/`continuous`), cron `schedule`, `max_attempts`, and optional delivery/chaining. ```yaml workflow: name: "Status-page watch" tasks: - type: task id: claim agent: data-table-agent operation: campaignClaim campaign_id: "<written by Studio 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] ``` ```campaign-config 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 - **`upsertRow` is insert-only, not keyed** — it does not match `matchFields`; use `chainStep` or explicit `col_<name>` columns for an idempotent per-item write, or `updateRows` to 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 `campaignStatus` before assuming it needs a manual nudge. - Every ledger operation is scoped to the caller's own account — there is no cross-tenant campaign surface today. ## 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` — the `batch`/`task`/`harness` types a campaign pipeline is built from. - `plungeai-scheduling` — cron cadence, `@once`, and `runAgain` self-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`](/skills/plungeai-campaigns/references/campaigns) — the `campaign-config` field table, every ledger operation (`campaignBegin`/`Claim`/`Complete`/`Fail`/`Release`/`Status`/ `AddItems`/`RetryFailed`/`SetStatus`/`Delete`/task rows/`chainStep`/`counterStep`), sizing, delivery channels, and gotchas. ## Reference pages <CardGroup cols={2}> <Card title="Campaigns — running a list to completion (the campaign ledger)" icon="file-text" href="/skills/plungeai-campaigns/references/campaigns"> A campaign claims a list of items (a data-table query, an agent's lister output, an uploaded CSV, or an inline list), runs each item through a CNL pipeline… </Card> </CardGroup> # Campaigns — running a list to completion (the campaign ledger) Source: https://docs-preview.plungeai.com/skills/plungeai-campaigns/references/campaigns <!-- sources-of-truth: agents/agents/campaign-agent/campaign-agent-design-5.0.md §8, agents/agents/campaign-agent/EXAMPLES.md, core/core-data-table-agent/README.md, core/core-data-table-agent/campaign-ledger.ts, core/core-data-table-agent/chain-step.ts, core/core-data-table-agent/counter-step.ts, orchestration/scheduler/README.md, orchestration/scheduler/CLAUDE.md | last-synced: 2026-09-23 --> A **campaign** claims a list of items (a data-table query, an agent's lister output, an uploaded CSV, or an inline list), runs each item through a CNL pipeline with per-item retries, and repeats on a cadence until the list ("cycle") is drained — then either re-cycles (`refill`/`reset`) or hands off to another campaign (`then`). It is PlungeAI's answer to "process these 280 rows every Monday" or "watch these 50 URLs forever." **Plain fact about the surface:** there is no dedicated public One API route or MCP tool for managing a campaign today (`https://api.plungeai.com` and `https://mcp.plungeai.com/v1` expose neither) — a campaign is authored visually in Ocean Studio via the **`plungeai-campaign-agent`** kind (CNL YAML + a `campaign-config` fenced block), and its runtime primitives are plain CNL `agent: data-table-agent` operations you can also call directly from a workflow you build yourself. This skill documents what exists; for the authoring UI itself use `plungeai-campaign-agent`. ## Discover the pieces first A campaign's pipeline is ordinary CNL, so discover its agents the normal way — never guess an id: `plungeai_list_agents {search: "<what the item-processing step needs>"}` (REST: `GET /v1/discovery/search?kind=agents&q=…`). `data-table-agent` itself is a registry agent id — confirm it live the same way. ## The `campaign-config` block A fenced ```` ```campaign-config ```` block sits after the CNL YAML; Studio parses it to open the ledger and create the scheduler job. | Field | Required | Meaning | |---|---|---| | `list` | yes | Where items come from: `table:` (a data-table project+table), `agent:` (a lister task whose JSON array feeds `items_from`), `csv: true` (uploaded rows), or `inline: [key, …]`. | | `cycle` | yes | Calendar bucket: `once` \| `hourly` \| `daily` \| `weekly` \| `monthly` \| `continuous`. | | `cycle_start` | when re-listing | `refill` (add new list rows, keep prior) or `reset` (fresh cycle from the list). | | `schedule` | yes | Cron for the run cadence, e.g. `"*/5 9 * * 1"` — the scheduler re-fires until the cycle drains (`plungeai-scheduling`). | | `max_attempts` | yes | Per-item retry cap before an item is marked `failed` (integer ≥ 1; the ledger column defaults to 2). | | `then` | no | Campaign id to hand the baton to when this one's cycle completes. | | `deliver` | no | Channels for the cycle-complete notice (below). | | `local` | no | `true` runs items on the user's own computer. | | `max_items` | no | Hard cap on total items claimed across the cycle. | | `task_types` | no | Per-row task/worker overrides. | | `learn` | no | Enables the ledger's recall/knowledge lane. | ## The CNL shape — claim, batch, complete ```yaml workflow: name: "RH price check" tasks: - type: task id: claim agent: data-table-agent operation: campaignClaim campaign_id: "<written by Studio 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}" ``` `type: batch` with `ledger: campaign` is what wires the batch's per-item outcome back into the campaign ledger automatically (complete/fail bookkeeping) — see `plungeai-workflows` for the general `batch` task type. An item's work can be a plain `task` (as above) or an open-ended `type: harness` mission (`plungeai-missions`) when the per-item work needs judgment, not a fixed call. ## The ledger primitives (`agent: data-table-agent` operations) Every operation is owner-scoped (`owner_uuid` — resolved from your account, not a field you pass by hand): | Operation | Purpose | |---|---| | `campaignBegin` | Create/upsert the campaign header at save time (list source, cycle kind, batch/concurrency/max_attempts, optional seed items). | | `campaignClaim` | Lease up to `batch_size` pending items for this run (`run_id`); opens a new cycle if the prior one drained and `cycle_start` allows it. Refuses to lease from a non-`active` campaign. | | `campaignComplete` | Mark one leased item done with its result — only a currently-leased row transitions (a stale duplicate is a safe no-op). | | `campaignCompleteHuman` | Complete a `worker_kind: "human"` row directly — human rows are never leased, so this is the only way one closes out. | | `campaignFail` | Record a failed attempt; the item returns to `pending` until `max_attempts`, then flips to `failed`. | | `campaignRelease` | Un-lease claimed-but-unfinished rows (e.g. a crashed run) back to `pending`. | | `campaignStatus` | Read the header + per-status item counts. | | `campaignAddItems` | Add items to the current (or a named) cycle; refuses past `max_items`. | | `campaignRetryFailed` | Re-queue `failed` items (optionally a specific key list) back to `pending`. | | `campaignSetStatus` | Pause/resume/mark done; pausing stamps `paused_by` (default `user:<owner>`; the scheduler's own zero-progress breaker stamps `auto:zero-progress`). | | `campaignDelete` | Soft-delete (`deleted_at` + `status='done'`); releases held leases; history stays queryable. | | `campaignTasks` / `campaignUpsertTasks` / `campaignSetTaskActive` | Read/edit the campaign's editable task-row list (the Task-app grid). | | `campaignResults` / `campaignPivot` | Recent per-item results (optionally rolled up per cycle) / a tasks-×-runs reporting grid. | | `chainStep` | The zero-AI "forever campaign" unit of work: bump a lane counter once per cycle (idempotent under at-least-once re-claims) and log a per-run row. | | `counterStep` | A pure per-cycle counter (`prev + step`), for the simplest possible repeating tally. | Full parameter shapes live in `core/core-data-table-agent/campaign-ledger.ts`, `chain-step.ts`, `counter-step.ts` — read those before hand-building a pipeline around one of these operations; nothing here is invented beyond what that code implements. ## Cadence — two ways a campaign keeps going 1. **Cron `schedule`** — an ordinary recurring scheduler job re-fires the pipeline until the cycle drains (the Forever Campaign ran on `*/5 * * * *`). This is the normal path when `campaign-config.schedule` is set. 2. **`runAgain` self-scheduling** — a campaign saved *without* a cron schedule ends its pipeline with `agent: scheduler, operation: runAgain, in: "1h"` (or another duration). This creates exactly ONE `@once` job for the workflow and **never stacks** — an existing pending `@once` job for the same workflow is re-timed, not duplicated. See `plungeai-scheduling` for `@once`/`runAgain` mechanics and cron/date-token reference in full. ## Sizing Keep `batch_size × seconds-per-item ÷ concurrency ≤ 600s` — comfortably inside the scheduler's execution window. The defaults (`batch_size: 40`, `concurrency: 5` at ~30s/item ≈ 4 minutes per run) are safe up to roughly 100 items per scheduled run; `batch_size`/`concurrency` are hidden authoring knobs, not something you expose to an end operator. ## Delivery on cycle-complete (`deliver`) - 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 output well under the smallest cap you use. - telegram / whatsapp targets must be paired to the owner first (a pairing code from Studio, `/pair <code>` from that chat); discord requires any active pairing. Unpaired targets are skipped. - email sends from the platform address; a bare target means the owner's address — any other address needs that holder's prior confirmation, else it's skipped silently. - slack: a bare target DMs the owner; a specific `chat_id`/`to` needs the owner to be a connected workspace member. ## Gotchas - **`upsertRow` is insert-only, not keyed** — it does not match `matchFields` or update in place, and a JSON-string `data` is not parsed. For an idempotent per-item write use `chainStep` or explicit top-level `col_<name>` columns (`insertRow`/`upsertRow` substitute `{item.*}` only into top-level string fields); to update an existing row use `updateRows`. - A partial cycle should never trigger a *dependent* report via `then` — chain only full completions to full completions (a data-collection campaign feeding a time-triggered analysis job is the safer pattern than chaining the analysis itself). - The zero-progress breaker auto-pauses a campaign after several consecutive completed-runs-that-completed-nothing (an all-failing list) — check `campaignStatus`/the Task app before assuming a stalled campaign needs a manual nudge. - Every ledger operation is scoped by the caller's own `owner_uuid` — there is no cross-tenant campaign management surface. # plungeai-discovery Source: https://docs-preview.plungeai.com/skills/plungeai-discovery Find the right thing on PlungeAI's live registry before building anything: agents, structured tools, models, skills, personas, connectors, and saved workflow templates, via hybrid semantic + keyword search (`plungeai_list_agents` MCP / `GET /v1/discovery/search` REST), full capability cards, a platform recommendation endpoint, tool-invocation contracts (`plungeai_get_tool_contract` / `GET /v1/tools/{id}`), and the template gallery (`plungeai_templates`). Use when picking an agent/tool/model/skill for a job, before the first call to an unfamiliar agent, deciding what to build from instead of from scratch, or debugging a refused/unknown id. Ids are live and active-only — never assert one from memory. For running a prompt-driven agent use `plungeai-agents`; for typed tool execution use `plungeai-tools-connectors`; for the model catalog use `plungeai-models`; for CNL workflow authoring use `plungeai-workflows`. [Download zip](https://skills.plungeai.com/plungeai-discovery.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-discovery/SKILL.md) The platform's capability catalog — agents, tools, models, skills, personas, connectors, workflows — is **live and changes without notice**. Discovery is not an optional first step, it is the mechanism that makes every other capability usable: an id you did not just get from a live lookup is likely to be refused at execution. ## Prerequisites - Self-service `ozk_` key from **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`). - MCP: `https://mcp.plungeai.com/v1`. REST: `https://api.plungeai.com`. ## Discovery first (this IS the discovery-first step) Never name an agent, tool, connector, or model in generated code, a workflow, or a reply unless that exact id came from one of the calls below in this session. "90-something agents" is flavor; the live catalog is the fact. ## 1. Search by capability — MCP ```json plungeai_list_agents {search: "convert pdf to markdown"} plungeai_list_agents {kind: "skills", search: "…"} plungeai_list_agents {agent_id: "exa-agent"} // full card ``` `kind` filters the catalog segment: `agents` (default, active-only) \| `personas` \| `experts` \| `skills` \| `models` \| `workflows` \| `connectors`. Full parameter table and failure modes — [`references/list-and-contract.md`](/skills/plungeai-discovery/references/list-and-contract). ## 2. Search by capability — REST ```bash curl -s "https://api.plungeai.com/v1/discovery/search?q=web%20search&kind=agents&limit=2" \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` Or let the platform pick for you: ```bash curl -s -X POST https://api.plungeai.com/v1/discovery/recommend \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{"type": "agent", "task": "summarize a long PDF into bullet points"}' ``` Full query params (`mode`, `fields`, `include=quality`, …), response shapes, and the full-card markdown route (`GET /v1/discovery/cards/{type}/{id}`) — [`references/search-and-recommend.md`](/skills/plungeai-discovery/references/search-and-recommend). ## 3. Inspect before you call — the tool contract Before the first call to an unfamiliar structured tool-agent (a card with a Parameters table), fetch its invocation contract — it IS the API docs, and (over MCP) carries the acting user's live credential status: ```json plungeai_get_tool_contract {agent_id: "markitdown"} ``` ```bash curl -s https://api.plungeai.com/v1/tools/markitdown -H "Authorization: Bearer ozk_YOUR_KEY" ``` ## 4. Starting points instead of from scratch — templates ```json plungeai_templates {action: "list", category: "research"} plungeai_templates {action: "get", template_id: "<id>"} ``` Browses Studio's own template gallery (ready-made workflows/agents/bots). Full detail — [`references/list-and-contract.md`](/skills/plungeai-discovery/references/list-and-contract). ## Gotchas - **Substring near-misses are not the same id.** `brave-agent` may exist while `brave-search` does not — take ids character-for-character from a result, never guess a variant. - **`count` is a page length, not a catalog total.** Page until a short page comes back; don't stop at `offset >= count`. - **Errors on `/v1/discovery/recommend` and `/v1/discovery/cards/{type}/{id}` are always the One API envelope.** The router normalizes the registry's own flat `{"error": "<string>"}` rejections into `{"error":{"code","message"}}` before they reach you (`code` is `not_found` on a 404, `invalid_request` otherwise; the original text lands in `message`) — `err.error.code` is always safe to read on these two routes. - **"My agents" is not the registry.** Users mean their saved workflows (`plungeai_list_workflows`) — the registry (`plungeai_list_agents`) is the platform's own capability catalog, for when YOU are composing. - **Discovery finds the contract; it doesn't execute anything.** Fetching a card or a contract never runs a workflow or spends a token — it's always safe to over-discover. ## Related skills - `plungeai-agents` — execute a prompt-driven agent once you've found it. - `plungeai-tools-connectors` — typed execution against a fetched contract, connected-account status. - `plungeai-models` — the model catalog (`GET /v1/models`) and money plane. - `plungeai-workflows` — instantiate a template into a saved workflow (`plungeai_templates {action: "use"}`), CNL authoring. - `plungeai-results-traces` — execution trace lookups (`GET /v1/traces/{id}`), a separate observability surface. - `plungeai-platform` — how discovery fits into the platform's five layers. ## Reference pages <CardGroup cols={2}> <Card title="Discovery over MCP — list_agents, get_tool_contract, templates (listing)" icon="file-text" href="/skills/plungeai-discovery/references/list-and-contract"> The registry is LIVE: agents come from the registry service at request time, no static manifest. </Card> <Card title="Discovery — /v1/discovery" icon="file-text" href="/skills/plungeai-discovery/references/search-and-recommend"> Discovery is the live catalog of everything the platform can do — agents, workflows, MCP servers, connectors, models — with hybrid semantic + keyword search… </Card> </CardGroup> # Discovery over MCP — list_agents, get_tool_contract, templates (listing) Source: https://docs-preview.plungeai.com/skills/plungeai-discovery/references/list-and-contract <!-- sources-of-truth: orchestration/mcp-gateway/tools.ts, orchestration/mcp-gateway/server.ts, orchestration/mcp-gateway/tool-exec.ts, orchestration/mcp-gateway/registry-cards.ts, orchestration/mcp-gateway/tool-outcome.ts, orchestration/mcp-gateway/extras.ts | last-synced: 2026-09-24 (list/contract half of the original discovery-and-execution.md, plus the plungeai_templates listing actions; the execute_agent/get_result half lives in plungeai-agents, the execute_tool half lives in plungeai-tools-connectors. Re-verified: ListAgentsSchema kind enum + boundedLimit against tools.ts, GetToolContractSchema against tool-exec.ts — all match, no drift found) --> The registry is LIVE: agents come from the registry service at request time, no static manifest. Only `status:active` agents are listed and callable over MCP; the same fence sits on the execution path, so an id you did not just get from a live search is likely to be refused. Take ids from search results, verbatim, every session. --- ## plungeai_list_agents **Purpose:** discover platform building-block agents from the live registry. NOT the user's saved workflows (that is `plungeai_list_workflows`). Read-only. **Parameters** | Param | Type | Notes | |---|---|---| | `search` | string ≤2000 | Hybrid semantic + keyword query over live agent cards. Describe the capability in natural language ("web search", "convert pdf to markdown", "post a message to a channel") and trust the ranking. | | `category` | string | Registry category filter. | | `agent_id` | string | Fetch ONE full card (markdown: operations, parameters, good-at examples, "Not for → use X instead" redirects). | | `kind` | enum | `agents` (default) \| `personas` \| `experts` \| `skills` \| `models` \| `workflows` \| `connectors`. Only `agents` is filtered active-only (the other kinds do not carry the tag). | | `limit` | int 1–100 | Default 25. | | `format` | `markdown` \| `json` | Response serialization; default markdown. | Every call also takes `user_request` (the user's ask, verbatim — every `plungeai_*` tool does; the platform uses it for routing and diagnostics). **Example** ```json {"user_request": "which agents can read SEC filings?", "search": "financial analysis and SEC filings", "limit": 5} ``` **Returns:** the registry's own markdown — ranked cards for a search, a full card for `agent_id`, the whole catalog (large) when unfiltered. Prefer `search`/`category` over an unfiltered listing. **Failures & fixes** - Unknown `agent_id` → "No registry card with id ... exists" plus a *Closest live matches* section. Not an error state — pick a listed live id or refine `search`. - Non-active `agent_id` → the card is withheld ("only `status:active` agents are listed and callable here") plus live alternatives. Same fix. - "Registry unavailable — try again shortly." → transient; retry once after a pause. **Rules:** never quote the catalog size as fixed; before using an unfamiliar agent, fetch its full card — cards carry parameters and redirects that prevent wrong-agent calls. --- ## plungeai_get_tool_contract **Purpose:** the exact invocation contract for one registry agent, generated live from its card: JSON Schema for parameters, the operation list (with approval-gated operations flagged), worked YAML examples, output shape, and LIVE per-provider credential status for the acting user. Fetch it before the first `plungeai_execute_tool` call to an unfamiliar agent — the contract IS the API docs. Read-only. **Parameters:** `agent_id` (required, string), `format` (`markdown` \| `json`, optional). **Example** ```json {"user_request": "what's the weather in Lisbon this weekend?", "agent_id": "weather-agent"} ``` (`weather-agent` here came from a live search in the same conversation — always derive the id from step 1's results, never from this page.) **Returns:** contract markdown + the same contract machine-readable at `structuredContent.contract` (one field of the ok envelope). The Credentials section is decisive: - `🔐 platform-managed` — nothing for the user to connect; just call. - `✅ connected as <email>` — the user's account is linked; call away. - `⚠️ NOT connected` / `expired — reconnect` — a required connection is missing: execution will stop with connect instructions until the user connects it (in a PlungeAI app → Connectors). Relay that BEFORE executing. The footer spells the run call: `plungeai_execute_tool {agent_id, operation: "<one of the operations>", params: {...}}`. Full typed-execution detail (params, outcome envelope, fences) lives in the `plungeai-tools-connectors` skill. **Failures & fixes:** unknown/inactive id → `unavailable` + alternatives (same fence as execution); "The registry did not answer" → `error`, retry in a few seconds. --- ## plungeai_templates — listing saved workflow templates **Purpose:** browse the platform's gallery of ready-made workflow/agent/bot templates (Studio's own template gallery — same `templates`/`template_versions` D1 rows and KV content, so usage counts stay consistent). This is discovery of **pre-built starting points**, distinct from `plungeai_list_agents` (registry building blocks) and `plungeai_list_workflows` (the user's own saved workflows). **Parameters** (listing actions only — `action: "use"` instantiates a template into a saved workflow and belongs to workflow authoring, see `plungeai-workflows`): | Param | Type | Notes | |---|---|---| | `action` | `"list"` \| `"get"` | `list` — the gallery; `get` — one template's full YAML | | `template_id` | string | Required for `get` (and for `use`) | | `category` | string | Filter for `list` | | `limit` | int 1–100 | `list` only | ```json {"user_request": "what workflow templates are available for research?", "action": "list", "category": "research", "limit": 10} ``` `list` returns a markdown table: Name, Kind, Category, Difficulty, Used (usage count), ID, Description — only `status:active` templates. `get` returns the template's name/description/category/difficulty plus its full YAML in a fenced block — read this before deciding whether to instantiate it with `action: "use"` (`plungeai-workflows`). **Failures & fixes:** `get`/`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. --- ## Putting it together — discover before you build ``` 1. plungeai_list_agents {search: "convert pdf to markdown"} → markitdown 2. plungeai_get_tool_contract {agent_id: "markitdown"} → schema; credentials 🔐 platform-managed 3. plungeai_templates {action: "list", category: "documents"} → any ready-made pipeline to start from instead? ``` Skip step 2 only for agents whose contract you fetched earlier in the same conversation. Execution (`plungeai_execute_agent`, `plungeai_execute_tool`, `plungeai_get_result`) is covered in `plungeai-agents` and `plungeai-tools-connectors`. # Discovery — /v1/discovery Source: https://docs-preview.plungeai.com/skills/plungeai-discovery/references/search-and-recommend <!-- sources-of-truth: orchestration/api-gateway/openapi.ts, orchestration/api-gateway/routes/discovery.ts, docs/ONE-API-DEVELOPER-GUIDE-2.0.md | last-synced: 2026-09-24 (discovery half of the original discovery-and-traces.md; the traces half lives in plungeai-results-traces. Re-verified against routes/discovery.ts: SEARCH_PARAMS whitelist, status defaults to active, 4xx/5xx normalization in forward(), KIND_TO_TYPE aliasing — all match, no drift found) --> Discovery is the **live catalog** of everything the platform can do — agents, workflows, MCP servers, connectors, models — with hybrid semantic + keyword search ranked server-side. Auth: `Authorization: Bearer ozk_YOUR_KEY` on every route here. ## Why discovery first Ids, capabilities, and counts change without notice. Any code (especially generated code) that names an agent, tool, MCP server, or model must have taken that id from a live discovery/list response — never from memory, docs, or this skill. Describe the capability in plain words and trust the ranking. ## GET /v1/discovery/search | Param | Values | Notes | |---|---|---| | `q` | free text | Natural-language capability query ("convert pdf to markdown") | | `kind` | `agents` \| `skills` \| `digital-twins` \| `personas` \| `experts` \| `backgrounds` \| `workflows` \| `models` \| `providers` \| `connectors` \| `plugins` \| `mcp-servers` | Catalog segment (plural) | | `type`, `category`, `tier` | strings | Additional filters | | `status` | default `active` | Leave defaulted — active means deployed and callable | | `limit`, `offset` | integers | Paging | | `mode` | `hybrid` \| `keyword` \| `vector` | Force one search leg (default hybrid). Response `searchMethod` values are `hybrid`/`vector`/`text` — keyword mode (and any keyword fallback) answers `"text"`, never `"keyword"` | | `fields` | `list` \| `summary` \| `full` | Card detail level | | `include` | `quality` | Attach measured eval scores per card | ```bash curl -s "https://api.plungeai.com/v1/discovery/search?q=web%20search&kind=agents&limit=2" \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "cards": [ { "id": "brave-agent", "name": "Brave Search", "type": "agent", "category": "search", "status": "active", "description": "Web search via Brave", "tags": ["search", "web"] }, { "id": "exa-agent", "name": "Exa Search", "type": "agent", "category": "search", "status": "active", "description": "Semantic web search", "tags": ["search"] } ], "count": 2, "searchMethod": "hybrid" } ``` The live response also carries a `query` echo object, and extra fields may appear — parse what you need, don't assert the exact shape. `count` is the returned page's length, not the catalog total. With `include=quality`, each card gains a `quality` block — `{"score": 1, "success_rate": 1, "runs": 12}` — or `null` when unmeasured (no eval runs yet on that card/tier). Treat `null` as "unknown", not "bad". `401` → missing/invalid `ozk_` key. ## POST /v1/discovery/recommend Ask the platform to pick the best card for a task instead of ranking yourself. Body: `{"type": "<card type, e.g. agent>", "task": "<what you need done>"}`. ```bash curl -s -X POST https://api.plungeai.com/v1/discovery/recommend \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"type": "agent", "task": "summarize a long PDF into bullet points"}' ``` ```json { "recommended": "pdf-agent", "card": { "id": "pdf-agent", "name": "PDF Agent", "type": "agent", "category": "documents", "status": "active", "description": "Convert and extract PDFs" }, "score": 0.91 } ``` `recommended` (and `card`) can be **`null`** when nothing matches — handle it; a card does not always come back. Errors — always the One API envelope (`{"error": {"code", "message", ...}}`), but the `code` differs by where the rejection happened: - Unparseable body → `400 {"error":{"code":"invalid_json","message":"JSON body required: { type, task }"}}`. - A parseable body the registry rejects → normalized to `400 {"error":{"code":"invalid_request","message":"Invalid type: x"}}` / `{"code":"invalid_request","message":"Task description required"}` — the registry's own flat `{"error": "<string>"}` is rewritten into the envelope before it reaches you (`message` carries the original text verbatim); it never reaches the caller as a bare string. Always safe to read `err.error.code`. - `429` → `rate_limited` (`Retry-After` header). - `5xx` from the registry never leaks through raw — it becomes a clean `502 {"error":{"code":"upstream_error", ...}}`. ## GET /v1/discovery/cards/{type}/{id} The full capability card as **markdown** (`text/markdown`) — the LLM-friendly view with operations, parameters, good-at examples, and "Not for → use X instead" redirects. Fetch it before building on an unfamiliar capability. `{type}` is the singular card type (`agent`, `skill`, `digital_twin`, `expert`, `background`, `workflow`, `model`, `provider`, `connector`, `plugin`, `mcp_server`) — the plural search `kind` values are accepted aliases. ```bash curl -s https://api.plungeai.com/v1/discovery/cards/agent/brave-agent \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```markdown # Brave Search (brave-agent) Web search via the Brave Search API. ## Operations - search — Run a web search (params: query, count?) ... ``` `404` when no such card exists — normalized to the One API envelope, `{"error":{"code":"not_found","message":"Card not found"}}`; a bad `{type}` is `400 {"error":{"code":"invalid_request","message":"Invalid type: …"}}`. The registry's own flat `{"error": "<string>"}` response is rewritten into this envelope (the original text lands in `message`) before it ever reaches you — same normalization as `/v1/discovery/recommend` above. ## Related Execution trace lookups (`GET /v1/traces/{id}`) are a separate observability surface — see the `plungeai-results-traces` skill, not this one. # plungeai-memory Source: https://docs-preview.plungeai.com/skills/plungeai-memory Read and write PlungeAI's per-user long-term memory (plungeai_memory: recall/remember/search_runs/get_run) and distill a session into a reusable skill with plungeai_learn — distinct from SharedMemory (a single run's output). Use when the user says remember this, asks what the agent knows about them, wants to review past runs, or wants findings saved as a skill for future runs. For a single run's output use `plungeai-results-traces`; for the skill/expert/persona/background/plugin capability system a saved skill feeds into use `plungeai-skills-plugins`. [Download zip](https://skills.plungeai.com/plungeai-memory.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-memory/SKILL.md) Two separate systems, never confuse them: **SharedMemory** holds one execution's task outputs (read with `plungeai_get_result`); **long-term memory** holds what the platform has learned about the user across every run, recalled automatically at mission start and written back with `plungeai_memory` or the agent's in-loop `memory` tool. ## Prerequisites - A self-service `ozk_` API key from **Dashboard → One API → Keys** (https://dashboard.plungeai.com), or an MCP client connected to `https://mcp.plungeai.com/v1`. - No discovery step needed for the memory tools themselves — they operate on the caller's own store. Discover agents you plan to reference (e.g. in `learn`) first: `plungeai_list_agents`. ## Reading and writing ``` plungeai_memory {action: "recall"} # read the durable store plungeai_memory {action: "remember", target: "user", # user | memory operation: "add", content: "Prefers weekly summaries, no emojis"} plungeai_memory {action: "search_runs", query: "competitor analysis"} plungeai_memory {action: "get_run", run_id: "…"} ``` `recall` returns the same MEMORY.md + USER.md snapshot a mission gets automatically at launch. Use `remember` any time the user says "remember this" — chat context alone does not persist. `replace`/`remove` need the exact `old_text`; a failed attempt returns the current entries so you can copy it verbatim and retry. ## Distilling a session into a skill — `plungeai_learn` ``` plungeai_learn {source: "<a URL, pasted text, or distilled findings from this chat>"} plungeai_learn {action: "list"} # your learned skills plungeai_learn {action: "forget", name: "<skill id>"} # delete one you own ``` `action` defaults to `learn` (async: poll `plungeai_get_workflow_status`, fetch with `plungeai_get_result`). Offer this "learn-back" move whenever a session produced real research worth reusing — the saved skill is private to the caller and can be declared on future mission/harness tasks (`plungeai-skills-plugins`). ## Gotchas - **Recall is a frozen snapshot** taken at run start — mid-run writes are durable but do not change the running prompt; two missions launched together never see each other's writes. - `episodes.md` (the append-only run log) is never injected into recall — pull run history explicitly with `search_runs` / `get_run`. - Memory is small and curated on purpose (MEMORY ~2200 chars, USER ~1375 default, clamped 500–20000) — write a few load-bearing facts, not a dump; every entry is threat-scanned twice (rejected at write, `[BLOCKED]`-replaced at snapshot build if it slipped through). - Bots do **not** set `memory_owner` (policy since 2026-08-23 — omit it entirely). A bot run reads/writes the owner's general memory namespace, shared across all their bots and runs; a hardcoded per-bot value is rejected by the harness guard unless it names the runner's own identity, so it is redundant at best. See `orchestration/BOT-CREATION.md`. - Delegate children never write memory (the `memory` tool is stripped) — one writer per run. - Standing company/product context that should apply to every run is NOT memory — it is a **background** card; a reusable method is a **skill** — see `plungeai-skills-plugins`. ## Related skills - `plungeai-results-traces` — SharedMemory / `plungeai_get_result`, a single run's output. - `plungeai-missions` — the mission lifecycle memory recalls into and writes from. - `plungeai-scheduling` — which scheduled job types keep the memory lifecycle. - `plungeai-skills-plugins` — declaring the skill `plungeai_learn` just saved. ## Reference - [`references/memory.md`](/skills/plungeai-memory/references/memory) — full SharedMemory-vs-long-term-memory comparison, the three-layer store (USER/MEMORY/episodes), budgets, safety scanning, namespaces, and the `plungeai_memory` / `plungeai_learn` MCP tool contracts. ## Reference pages <CardGroup cols={2}> <Card title="Memory — run data (SharedMemory) vs long-term memory. Two systems, never confuse them" icon="file-text" href="/skills/plungeai-memory/references/memory"> PlungeAI has TWO memory systems with different jobs: </Card> </CardGroup> # Memory — run data (SharedMemory) vs long-term memory. Two systems, never confuse them Source: https://docs-preview.plungeai.com/skills/plungeai-memory/references/memory <!-- sources-of-truth: core/core-memory/core-memory.ts, CLAUDE.md (SharedMemory usage), orchestration/BOT-CREATION.md (memory_owner policy), orchestration/mcp-gateway/server.ts, orchestration/mcp-gateway/tools.ts, orchestration/mcp-gateway/extras.ts, orchestration/api-gateway/openapi.ts, orchestration/cnl-engine/schema-types.ts | last-synced: 2026-09-24 --> PlungeAI has TWO memory systems with different jobs: | | **SharedMemory** | **Long-term memory** | |---|---|---| | Holds | Every task's output within/after a run | What the agent LEARNED about the user and its work | | Keyed by | `(workflow_id, task_id, user)` | Per user (or per bot namespace) | | Lifetime | Per execution, durable for retrieval | Standing, across all runs | | You read it via | `plungeai_get_result`, `/v1/*/results/…` | Automatic recall in runs; `plungeai_memory` | | You write it via | Never directly — agents store results | `plungeai_memory remember`; the agent's own `memory` tool | "Fetch what that run produced" is SharedMemory. "Remember that the user prefers weekly summaries" is long-term memory. ## SharedMemory — the run-data fabric Every task result — including single agent calls — is stored under `(workflow_id, task_id)` scoped to your user. That is why every execution acknowledgement returns those ids: they are redemption tickets. ``` # MCP — final result (full conversation thread for conversational runs) plungeai_get_result {workflow_id: "exec-…"} # One step of a fan-out plungeai_get_result {workflow_id: "exec-…", task_id: "web"} ``` ```bash # One API curl -s https://api.plungeai.com/v1/workflows/results/{workflowId}/{taskId} \ -H "Authorization: Bearer ozk_YOUR_KEY" curl -s https://api.plungeai.com/v1/agents/results/{workflowId}/{taskId} \ -H "Authorization: Bearer ozk_YOUR_KEY" # 200 {content, content_type, workflow_id, task_id} | 404 not_ready ``` Facts to rely on: - `404 not_ready` = still running (or a beat behind) — poll; not an error. - Results are scoped to the executing user — you cannot redeem another user's ids. - The final result of a run lists its steps (MCP renders them); open any step in full with its `task_id`. Use this to inspect ONE branch of a parallel block instead of re-running. - Within a workflow, data handoff between tasks IS SharedMemory — automatic; never hand-wire results between tasks in YAML. - A scheduler run id is not a SharedMemory id: go through `plungeai_schedule {action: "runs"}` and use its Execution ID column (`plungeai-scheduling`). ## Long-term memory — the agent's durable brain Per user, three layers of plain markdown: | Layer | File | What it holds | |---|---|---| | L3 | `USER.md` | The agent's learned model of the user (preferences, context) | | L2 | `MEMORY.md` | Curated agent notes shared across this user's missions | | L1 | `episodes.md` | Append-only run log: goal + self-reported outcome per mission | ### Recall — a frozen snapshot per run At mission start the platform builds ONE snapshot of the **curated stores only — MEMORY.md + USER.md. `episodes.md` is never injected** (task outcomes go stale; pull run history explicitly with `search_runs` or the mission's `recall` tool). The snapshot is prepended to the agent's system prompt. Mid-run writes are durable but do **not** mutate the running prompt (prompt-prefix stays cache-stable). So: what a mission "knows" is fixed at launch; what it learns benefits the NEXT run. Two missions launched together do not see each other's writes. ### Writing - **In-loop:** the agent's `memory` tool (missions write learnings as they work; episodes append automatically at run end). - **From outside:** `plungeai_memory`: ``` plungeai_memory {action: "recall"} # read the durable store plungeai_memory {action: "remember", target: "user", # user | memory operation: "add", # add | replace | remove | read content: "Prefers weekly summaries, no emojis in reports"} plungeai_memory {action: "search_runs", query: "competitor analysis"} plungeai_memory {action: "get_run", run_id: "…"} ``` Use `remember` whenever the user says "remember this". Note the split: `recall` reads the curated stores; the **run journal** (`search_runs`/`get_run`) is separate and deliberately NOT part of recall — history is queried, not ambient. ### Budgets — memory is curated, not a dump The stores are small on purpose (defaults: MEMORY ~2200 chars, USER ~1375; configurable per user, clamped to 500–20000). Writes beyond the limit force curation — replace/remove stale entries rather than appending forever. Write memory like an engineer writes a runbook: few, load-bearing, current facts. Ten vague notes crowd out the one that matters. ### Safety Every entry is threat-scanned twice: at write (a prompt-injection-looking entry is **rejected**) and at snapshot build (a poisoned stored entry is replaced with a `[BLOCKED]` placeholder; the raw text stays inspectable by the user). Do not try to store instructions-to-future-agents phrased as commands — that is exactly the pattern the scanner exists to stop. Store facts. ## Namespaces and special runs - **Bots:** policy since 2026-08-23 is to **omit `memory_owner` entirely** — the first 20 bots were authored with a hardcoded `memory_owner: "<ownerUserId>:bot:<workflowId>"` and all had it stripped. Without it, a bot run reads/writes the **owner's general memory namespace**, shared across all their bots and runs ("check memory" / "store in memory" phrasing still works; prompts are a bit larger since the recall snapshot is built from the whole store). The harness guard (`resolveMemoryUser`) honors a hardcoded `memory_owner` only when it names the runner's own identity — anything else is rejected with a warning and falls back to the owner's store, so a copied YAML can never read or write another user's memory even if it tries. Full policy and rationale: `orchestration/BOT-CREATION.md`. (Do not confuse this with a workflow's `followup.memory_scope: all_tasks|last_task`, which only scopes follow-up chat context.) - **Scheduled runs** keep the full per-user memory lifecycle — a daily mission genuinely accumulates. Only system jobs and heartbeat condition checks are memory-free (heartbeat is a user-facing job type — see `plungeai-scheduling` — whose ticks are watch-and-notify checks, not learning runs). - **Delegate children** never write memory: the `memory` tool is stripped from fan-out children by design — one writer per run. ## Choosing the right memory move | Need | Move | |---|---| | Output of a run/step | `plungeai_get_result` (+ `task_id`) | | Pass data between workflow steps | Nothing — automatic | | "Remember X about me/us" | `plungeai_memory remember` | | Mission should apply past learnings | Automatic recall — just run it; curate memory if recall is noisy | | "What did we do about X before?" | `plungeai_memory search_runs` → `get_run` | | Standing company/product context for many runs | Not memory — a **background** card (`plungeai-skills-plugins`) | | Reusable method/knowledge pack | Not memory — a **skill**, created with `plungeai_learn` (below) | The last two rows matter: memory is per-user learned state. Shared, versioned, deliberately-authored context belongs in backgrounds and skills, where injection is explicit and reviewable. --- ## MCP tool: `plungeai_memory` **Purpose:** the user's long-term memory. Two stores, deliberately separate: the durable memory that `recall` reads (and `remember` writes), and the run journal of past mission runs (`search_runs`/`get_run`). **Actions** | Action | Requires | Notes | |---|---|---| | `recall` | — | Everything the platform remembers about the user (the same recall missions get automatically). | | `remember` | `content` (add/replace) or `old_text` (remove); neither for read | Durable write. `target`: `user` (profile facts) \| `memory` (working knowledge, default). `operation`: `add` (default) \| `replace` (needs `old_text` + `content`) \| `remove` (needs `old_text`) \| `read`. `recall` sees writes immediately. | | `search_runs` | `query` | Search the run journal (optional `limit`, default 10). | | `get_run` | `run_id` | One journal entry in full. | **Example:** `{"user_request": "remember that I prefer summaries under 200 words", "action": "remember", "target": "user", "content": "Prefers summaries under 200 words"}` **Returns:** `recall` → the memory document (or "No memory recorded yet."); `remember` → "Saved to your user profile/memory ... recall will see it immediately."; failed writes return the error plus the CURRENT entries so a `replace`/`remove` can be retried with an exact `old_text`. **Failures & fixes:** "content is required for remember" / "query is required for search_runs" / "run_id is required for get_run" → supply them. A `replace`/`remove` that misses names the current entries — copy `old_text` verbatim from that list and retry. Use `remember` whenever the user says "remember this" — chat context alone does not persist. --- ## MCP tool: `plungeai_learn` **Purpose:** distill a source into a reusable skill, saved PRIVATE to the user — future runs can inject it. The source can be a URL, pasted text/markdown, or a description of what was just accomplished in this chat (learn-back). Runs the platform's `learn` agent card, which resolves live at run time. **Async by default.** **Parameters** | Param | Type | Notes | |---|---|---| | `action` | `learn` (default) \| `list` \| `forget` | `learn`: distill `source` into a skill. `list`: your learned skills. `forget`: delete one (`name` required). | | `source` | string | Required for `action: learn` (a URL, pasted text/markdown to distill, or a description of what you just did). Not used by `list`/`forget`. | | `name` | string (kebab-case) | On `learn`: optional skill id — the agent picks one if omitted. On `forget`: required (the id from `action: list`). | | `mode` | `sync` \| `async` | Only applies to `learn`; default async. | **Example (learn):** `{"user_request": "save what we learned about CNL debugging as a skill", "source": "Distilled findings from this session: ...", "name": "cnl-debugging"}` **Example (list):** `{"user_request": "what skills have I saved?", "action": "list"}` **Example (forget):** `{"user_request": "delete my cnl-debugging skill", "action": "forget", "name": "cnl-debugging"}` **Returns:** - `learn`, async (default): "Started distilling `<id>` (async)..." → poll `plungeai_get_workflow_status`, fetch with `plungeai_get_result` (the result names the saved skill). - `list`: a table of your learned skills (`- \`id\` — description`), or "No learned skills yet." - `forget`: "Forgot skill `<name>`." **Failures & fixes:** `learn` without `source` → `needs_input`. `forget` without `name` → "`forget` needs `name` (the skill id from `action: list`)." `forget` on an id you don't own, or that doesn't exist → "Not yours to delete" / "No skill named `<name>`. Use `action: list` to see yours." Authentication required (needs a real user key); unreachable URLs on `learn` surface in the run result — retry with pasted text instead. This is the "learn-back" move: when a session produced real research, offer to distill it so future runs can inject it as a skill — see `plungeai-skills-plugins` for how a saved skill gets declared and injected on later runs. # plungeai-missions Source: https://docs-preview.plungeai.com/skills/plungeai-missions Run bounded autonomous PlungeAI agent missions (type: harness) — a goal, a tool fence, an iteration cap, and self-checked success criteria, via plungeai_run_mission or a harness workflow task. Use when the steps to reach a goal are not known in advance, when you need one open-ended researcher/verifier/analyst loop instead of a guessed chain of small tasks, or when the user asks for a bounded agent run. For a fixed pipeline of known steps use `plungeai-workflows`; for cron-scheduled missions use `plungeai-scheduling`; for a list-to-completion campaign ledger use `plungeai-campaigns`. [Download zip](https://skills.plungeai.com/plungeai-missions.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-missions/SKILL.md) A mission gives one agent a `goal`, a standing purpose, a fenced tool set, an iteration cap, and success criteria it self-checks before finishing — then runs a real ReAct loop (think → tool call → result → …) against it, hard-stopped at every bound. Reach for a mission when the steps to reach the goal are NOT known in advance; use a plain workflow (`plungeai-workflows`) when they are. ## Prerequisites - A self-service `ozk_` API key from **Dashboard → One API → Keys** (https://dashboard.plungeai.com), or an MCP client already connected to `https://mcp.plungeai.com/v1`. - Confirm identity first: `plungeai_whoami`. ## Discovery first Never guess a skill, expert, persona, plugin, or MCP server id — a wrong id degrades to a silent warning, not a hard failure. Look ids up live: `plungeai_list_agents {kind: "skills"|"experts"|"personas"|"connectors", search: "<topic>"}` (REST: `GET /v1/discovery/search?kind=…&q=…`). ## Running a mission — the two doors **Quick, from an agent context** — `plungeai_run_mission` accepts a fixed subset of the mission contract: ``` plungeai_run_mission {goal, mission?, allowed_tools?, max_iterations? (≤50), success_criteria?, persona?, skills?, mode?: "sync"|"async"} ``` ```json {"user_request": "research the EU AI Act's impact on medical devices", "goal": "Produce a sourced brief on how the EU AI Act affects medical-device software vendors", "max_iterations": 12, "success_criteria": ["cites primary sources", "covers timelines and penalties"]} ``` Defaults to async: poll `plungeai_get_workflow_status`, fetch with `plungeai_get_result`. A paused run (`⏸ AWAITING USER APPROVAL` / `AWAITING USER`) is relayed to the user and resumed with `plungeai_continue`. **Full control, as a workflow task** — anything beyond that subset (`experts`, `backgrounds`, `plugins`, `mcp`, `model`/`provider`, `effort`, `max_parallel`, `permissions`, `memory_owner`, `local`) requires a one-task `type: harness` workflow, run with `plungeai_execute_workflow`: ```yaml name: Claim verification tasks: - type: harness goal: "Verify the claims in {input} and produce a sourced verdict" mission: | You are a careful researcher. Verify claims against primary sources. Refuse to conclude beyond the evidence. skills: [research] effort: standard allowed_tools: [web_search, web_fetch, task_complete] success_criteria: - Every verdict cites at least one primary source ``` Or reuse a pre-built agent card: `mission_ref: research-analyst` (equivalent shorthand: a single-token `mission: research-analyst`). Cards are also directly schedulable — see `plungeai-scheduling`. ## The tool fence — the core safety mechanism `allowed_tools` is a hard whitelist: an out-of-fence tool call is refused by the runtime, never just discouraged. Always include `task_complete`. Give the smallest set that can achieve the goal — a verification mission needs `web_search, web_fetch, task_complete`, not the file tools. Two loop runtimes exist (the full-surface default, and the thin `universal-agent` registry-first fence, selected with `agent:`); an explicit `allowed_tools` always wins over either default. Full catalog and the agent fence / money-class protection: [`references/missions.md`](/skills/plungeai-missions/references/missions). ## Gotchas - No per-task `retry` on harness — mission runs are not idempotent; check `plungeai_executions` before re-firing anything with side effects. - `success_criteria` are self-checked by the agent — treat them as guidance-grade, not proof. - Merge order for cards is last-wins per key (card → workflow root → task), and **arrays REPLACE, never union** — a task-level `skills: [x]` replaces the whole card list. - A run pauses (never dies) on `ask_user` questions or `permissions: ask` gates; resume with `plungeai_continue`, never retry around a pause. - Memory: the platform recalls the owner's long-term memory as a frozen snapshot at run start and writes back durably mid-run — see `plungeai-memory`. ## Related skills - `plungeai-workflows` — plain multi-step CNL pipelines; embed a mission as one task. - `plungeai-scheduling` — cron a mission (or a `mission_ref` card) to run on its own. - `plungeai-memory` — the recall/write lifecycle a mission runs against. - `plungeai-skills-plugins` — the `skills`/`experts`/`persona`/`backgrounds`/`plugins`/`mcp` capability fields. - `plungeai-results-traces` — read a mission run's status, output, and trace. - `plungeai-campaigns` — running a list to completion instead of one bounded goal. ## Reference - [`references/missions.md`](/skills/plungeai-missions/references/missions) — full field reference, tool/agent fences, recursion guards, pre-built cards, and the `plungeai_run_mission` MCP tool contract. ## Reference pages <CardGroup cols={2}> <Card title="Missions — bounded autonomous agent runs (type: harness)" icon="file-text" href="/skills/plungeai-missions/references/missions"> A mission bounds what an agent may do for ONE goal: a standing purpose, a fenced tool set, an iteration cap, optional identity/knowledge injection, and… </Card> </CardGroup> # Missions — bounded autonomous agent runs (type: harness) Source: https://docs-preview.plungeai.com/skills/plungeai-missions/references/missions <!-- sources-of-truth: orchestration/cnl-engine/harness-mission.ts, orchestration/cnl-engine/schema-types.ts (InlineMission), orchestration/HARNESS-README.md, orchestration/BOT-CREATION.md (memory_owner policy), orchestration/mcp-gateway/server.ts, orchestration/mcp-gateway/tools.ts | last-synced: 2026-09-24 --> A **mission** bounds what an agent may do for ONE goal: a standing purpose, a fenced tool set, an iteration cap, optional identity/knowledge injection, and self-checked success criteria. You give a `goal`; the platform runs a real ReAct tool loop (think → tool call → result → …) against it, hard-stopped at every bound. This is the capability to reach for when the steps are NOT known in advance — one harness task, not a chain of guessed small tasks. Missions are humans-and-workflows-in-control by construction: the agent executes *inside* the bounds; it cannot widen them. ## Minimal and typical ```yaml name: Claim verification tasks: - type: harness goal: "Verify the claims in {input} and produce a sourced verdict" mission: | You are a careful researcher. Verify claims against primary sources. Refuse to conclude beyond the evidence. skills: [research] effort: standard allowed_tools: [web_search, web_fetch, task_complete] success_criteria: - Every verdict cites at least one primary source ``` Or from an agent context, without YAML — but note the MCP tool accepts only a **subset** of the mission contract: ``` plungeai_run_mission {goal, mission?, allowed_tools?, max_iterations? (≤50), success_criteria?, persona?, skills?, mode?: "sync"|"async"} ``` Those are ALL the fields. Anything beyond them — `experts`, `backgrounds`, `plugins`, `mcp`, `model`/`provider`, `effort`, `max_parallel`, `permissions`, `memory_owner`, `local` — requires authoring a one-task `type: harness` workflow (the full table below) and running it via `plungeai_execute_workflow`. Defaults to async — poll `plungeai_get_workflow_status`, fetch with `plungeai_get_result`. The run recalls and writes long-term memory automatically (see `plungeai-memory`). If status reports `⏸ AWAITING USER APPROVAL` or `AWAITING USER`, relay it and continue with `plungeai_continue` after the user decides. ## The authoring contract — flat peers, one internal shape Capability fields are written FLAT on the task (the engine folds them into the mission internally). The nested `mission: { … }` object form also works; flat wins per key over nested. ### Full field reference | Field | Type | What it bounds | |---|---|---| | `goal` | string | The per-run input — becomes the agent's prompt | | `mission` | multi-line string | Standing purpose → system-prompt frame. A SINGLE-TOKEN string is a card reference instead (below) | | `persona` | string | One voice per run (`digital_twin` alias; `personas: [x]` → first entry) | | `skills` | string[] | Instruction packs — first 5 eager, rest on demand (`plungeai-skills-plugins`) | | `experts` | string[] | Domain lenses — first 3 eager (`plungeai-skills-plugins`) | | `backgrounds` | string[] | Ambient context cards — first 3 eager, injected first | | `plugins` | string[] | Bundles: skill index + MCP servers + scripts (`plungeai-skills-plugins`) | | `mcp` | string[] | MCP server ids connected in-loop | | `model`, `provider` | string | Model/provider override (`plungeai-models`) | | `effort` | `quick`\|`standard`\|`deep` | Turn-budget preset: **4 / 12 / 20** turns | | `max_turns` | number | Explicit loop cap (alias `max_iterations`); wins over `effort`; runtime default 50 | | `max_tokens` | number | Per-turn OUTPUT token budget for the loop's model calls (runtime default 16384) | | `budget_usd_run` | number | Per-run spend cap in USD — the loop prices its running token cost each turn and stops (`stopReason: "budget"`) once exceeded; absent = no cap | | `max_parallel` | number | Widest fan-out one `delegate` call may spawn — cap-and-refuse, never silently batched | | `allowed_tools` | string[] | The tool fence (below) | | `allowed_agents` | string[] \| `'all'` | Agent fence for `call_agent` | | `denied_agents` | string[] | Subtracted from the agent fence | | `permissions` | map tool → `allow`\|`ask`\|`deny` | Per-tool human gate: `ask` pauses the run with `needs_approval` before the tool executes; `deny` rejects the call. Keys may be tool names or permission classes (`send`\|`write`\|`pay`\|`delete`) | | `permission_locks` | string[] | Admin-locked permission classes: 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 DB at the Studio execute boundary, not trusted from raw YAML for enforcement — carried through, not authored | | `success_criteria` | string[] | Self-checked statements the agent verifies before finishing | | `instructions` | string | Extra author instructions, appended after skills — always lands | | `python_executor` | `auto`\|`pyodide`\|`anthropic`\|`gemini` | `run_python` tier routing | | `memory_owner` | string | Memory namespace override — **do not use; omit entirely** (policy since 2026-08-23). Identity does not belong in mission 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 `plungeai-memory` and `orchestration/BOT-CREATION.md` | | `local`, `local_agents` | bool, string[] | Local bot: actions route to the user's own machine via the desktop daemon (cloud brain, local hands); requires a connected local node | ## The tool fence `allowed_tools` is a hard whitelist — only listed tools ever reach the LLM; an out-of-fence call is refused by the runtime, not merely discouraged. Omit it and the loop runtime applies its own **fail-closed default fence**. The full loop-tool catalog (fence vocabulary): `read_file`, `write_file`, `edit_file`, `list_files`, `search_files`, `delete_file`, `web_search`, `web_fetch`, `load_skill`, `memory`, `knowledge`, `skill_manage`, `recall`, `recall_history`, `delegate`, `local_agent`, `registry_search`, `registry_lookup`, `call_agent`, `invoke_workflow`, `run_python`, `ask_user`, `platform_action`, `task_complete`. Fence design rules: - **Always include `task_complete`** — it is how a run ends cleanly. - Smallest set that can achieve the goal. A verification mission needs `web_search, web_fetch, task_complete` — not the file tools. - `ask_user` keeps human-question continuations available on every surface; include it when the goal may need clarification mid-run. - Two loop runtimes exist: the default full-surface runtime (all 24 tools; in unattended runs — the engine/bot default — `platform_action` is stripped from that *default* fence, which is why a scheduled mission can behave differently from the same mission run interactively) and `universal-agent` (thin default fence: the registry triad `registry_search` + `registry_lookup` + `call_agent`, plus research + `load_skill` + `ask_user` + `task_complete` — an unfenced universal-agent mission CAN call registry agents) — select with `agent:` on the harness task. An explicit `allowed_tools` always wins over either default. ## The agent fence and money-class protection `call_agent` lets the loop invoke registry agents. `allowed_agents: [a, b]` limits it to those; `'all'` opens the catalog minus `denied_agents`. **Payment/blockchain-class agents stay deny-unless-explicitly-named even under `'all'`** — naming them is the only way a mission can touch money, and `permissions: {call_agent: ask}` adds a human gate on top. This is a trust fence: surface refusals, never work around them. ## Recursion and fan-out guards - `delegate` spawns parallel child agents; children get a minimal default tool set and ALWAYS have `delegate`, `invoke_workflow`, and `memory` stripped — no fan-out explosions, no child memory writes. - Orchestrator depth is propagated (`depth` → children send `depth+1`) and hard-capped (default max depth 3); a too-deep dispatch is refused. - `max_parallel` caps one delegate call's width by refusal, never by serializing — silent batching would multiply wall clock. ## Pre-built agent cards (`mission_ref`) A stored agent card (markdown frontmatter + body, compiled by the platform) packages a whole mission for reuse: ```yaml - type: harness goal: "{input}" mission_ref: research-analyst # canonical; `pack:` is an alias # equivalent shorthand: mission: research-analyst (single token = card id) ``` A card with no explicit `agent:` hosts on `universal-agent` — predict its default fence (the thin one above) accordingly. **Merge order, per key, last wins: card → workflow root → task.** Two rules that bite: - **Arrays REPLACE, never union.** Task-level `skills: [x]` replaces the card's skill list entirely; an explicit `skills: []` deliberately clears it. - A blank inline `mission` text does not override the card's purpose; any non-blank inline text does. Cards are also directly schedulable: `plungeai_schedule {action: "create", mission_ref: "…", schedule: "0 7 * * *", …}` (`plungeai-scheduling`). ## Memory lifecycle At run start the engine recalls the owner's long-term memory as a **frozen snapshot** prepended to the system prompt; the loop's `memory` tool writes back durably (writes do not mutate the running prompt). Bots do **not** set `memory_owner` — policy since 2026-08-23 is to omit it entirely; a bot run reads and writes the owner's general memory namespace, shared across all their bots and runs (a hardcoded per-bot value is rejected by the harness guard unless it names the runner's own identity, so it is redundant at best). Scheduled user runs keep the full memory lifecycle; only system/heartbeat jobs run memory-free. Details, limits, threat-scanning, and the bot-memory policy: `plungeai-memory`. ## Execution semantics worth engraving - **No per-task `retry` on harness.** Mission runs are not idempotent — the engine never re-fires them automatically, and neither should you without checking what the first run already did (`plungeai_executions`). - `success_criteria` are self-checked by the agent (no external verifier in the loop) — write them as verifiable statements, and treat them as guidance-grade, not proof. - Runs pause (never die) on `ask_user` questions and `permissions: ask` gates — status carries a `continuation` block; resume with `plungeai_continue` (`message` for answers, `approve: true` only after an explicit human yes). - Budget honestly: `quick` (4 turns) suits a lookup-and-answer; `deep` (20) a real investigation; explicit `max_turns` for anything unusual. A run that hits its cap ends with whatever it has — better a tight cap and a follow-up mission than an unbounded loop. ## Mission vs workflow — the decision | Signal | Choose | |---|---| | Steps enumerable in advance, repeatable | Workflow of plain tasks (`plungeai-workflows`) | | Open-ended goal, tool choice needs judgment | ONE harness mission | | Both: fixed pipeline with one judgment-heavy stage | Workflow with a single embedded `type: harness` task | The classic failure is decomposing an open-ended goal into six guessed tasks — the guesses are wrong and the pipeline is brittle. Give the goal to one fenced mission instead. --- ## MCP tool: `plungeai_run_mission` **Purpose:** run a bounded autonomous agent mission — a loop agent with a goal, a tool fence, and an iteration cap. It recalls and writes the user's long-term memory automatically. **Async by default** (missions are long); pass `mode: "sync"` only for short, tightly-bounded goals. **Parameters** | Param | Type | Notes | |---|---|---| | `goal` | string ≤65536, required | What to achieve. | | `mission` | string | The mission brief / operating instructions (default: a capable general agent that cites sources). | | `allowed_tools` | string[] ≤50 | The tool fence (default `web_search`, `web_fetch`, `task_complete`). The agent cannot use tools outside it. | | `max_iterations` | int 1–50 | Loop cap (default 8). | | `success_criteria` | string[] ≤20 | Explicit done-conditions. | | `persona` | string | Persona id to inject. | | `skills` | string[] ≤20 | Skill ids to inject. | | `mode` | `sync` \| `async` | Default async. | **Example** ```json {"user_request": "research the EU AI Act's impact on medical devices", "goal": "Produce a sourced brief on how the EU AI Act affects medical-device software vendors", "max_iterations": 12, "success_criteria": ["cites primary sources", "covers timelines and penalties"]} ``` **Returns (async):** "Started mission `<id>` (async). Poll plungeai_get_workflow_status with this id, then fetch output with plungeai_get_result once completed. The agent recalls and writes long-term memory automatically. If the status reports ⏸ AWAITING USER APPROVAL or AWAITING USER, relay it to the user and continue with plungeai_continue." — follow that script. Sync mode returns the finished result (or a ⏸ pause) directly. **Failures & fixes:** timeouts in sync mode → go async (the remediation says so). A mission's own tool failures are the agent's to work around inside its loop; the envelope classifies anything terminal. Note: async runs emit no progress notifications — poll for status instead of waiting for a stream. # plungeai-models Source: https://docs-preview.plungeai.com/skills/plungeai-models Model routing on PlungeAI: how agents/workflows/missions resolve a model through the platform's provider factory (`model`/`provider` fields on a task or mission), and the separate OpenAI-compatible money-plane API (`https://api.plungeai.com/v1/chat/completions`, `/v1/embeddings`, `/v1/models`) with `sk-ocean-` keys, `models[]` fallback routing, `@preset/` bundles, and response caching for your own code. Use when steering which model a task/mission runs on, calling chat/embeddings directly from your app, choosing fallback candidates across providers, or debugging a 4xx/5xx from `/v1/chat/completions`. For discovering agents/tools/models by capability use `plungeai-discovery`; for running an agent or tool use `plungeai-agents` / `plungeai-tools-connectors`; for authoring CNL workflows that steer `model` per task use `plungeai-workflows`. [Download zip](https://skills.plungeai.com/plungeai-models.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-models/SKILL.md) PlungeAI touches models in two distinct places, with two different keys: 1. **Inside platform runs** — agents, workflows, and missions resolve models through the platform's **provider factory** (a fleet of per-provider Workers behind one selection layer). You steer it with `model`/`provider` fields on tasks and missions. 2. **The money plane** — an OpenAI-compatible inference API at `https://api.plungeai.com` (`/v1/chat/completions`, `/v1/embeddings`, `/v1/models`) for YOUR code, with routing/fallback/caching on top. ## Prerequisites - Self-service `ozk_` key (execution planes: agents/workflows/MCP) from **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`). - The money plane uses a **different key**: `sk-ocean-` (same dashboard). Mixing the two up is the most common 401. - Base surfaces: `https://mcp.plungeai.com/v1` (MCP) / `https://api.plungeai.com` (REST). ## Discovery first Model catalogs churn weekly. `GET /v1/models` (with an `sk-ocean-` key) is the priced, live catalog routing candidates are drawn from — discover it at runtime, never hardcode a model list in generated code. ## 1. Steering the model inside a run (provider factory) Flat fields on a task, passed through to the agent: ```yaml - type: task id: analyze agent: llm-agent prompt: "…" model: claude-sonnet-5 maxTokens: 4096 ``` Or on a harness mission (mission-level override): ```yaml - type: harness goal: "…" mission: | You are a careful researcher. model: claude-sonnet-5 provider: anthropic ``` Omit `model` and the agent/provider default applies — usually the right call. Full behavior (pattern-based capability detection so new model generations work with no platform change, auto-continue on truncation, per-task usage/cost) — [`references/provider-factory.md`](/skills/plungeai-models/references/provider-factory). ## 2. The money plane for your own code Drop-in `base_url` swap for any OpenAI-compatible client: ```bash curl -s https://api.plungeai.com/v1/chat/completions \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" -H "Content-Type: application/json" \ -d '{"model": "anthropic/claude-sonnet-5", "messages": [{"role": "user", "content": "Say hello"}]}' ``` Ordered fallback across providers, reordered by rolling stats before the first attempt: ```json {"models": ["anthropic/claude-sonnet-5", "openai/gpt-5"], "sort": "price", "messages": [{"role": "user", "content": "…"}]} ``` Embeddings and the priced catalog: ```bash curl -s https://api.plungeai.com/v1/embeddings \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" -H "Content-Type: application/json" \ -d '{"model": "openai/text-embedding-3-small", "input": ["hello", "world"]}' curl -s https://api.plungeai.com/v1/models -H "Authorization: Bearer sk-ocean-YOUR_KEY" ``` Full request fields (`models[]`, `sort`, `@preset/<slug>`, response cache, guardrails), the complete error catalogue, and streaming — [`references/money-plane.md`](/skills/plungeai-models/references/money-plane). ## Gotchas - **Two key types.** `ozk_` runs agents/tools/workflows/MCP; `sk-ocean-` runs the money plane. A key from the wrong tier 401s. - **Honest billing.** The response `model` field is the slug that ACTUALLY served the request — after a failover it can differ from what you asked for. Bill, log, and display on the response value, never the requested one. - **Never hardcode model slugs.** `GET /v1/models` is the only authority; populate any model picker in generated code from it at runtime. - **Nested `config` is a special case.** A `config: {model, maxTokens}` block is tolerated by `llm-agent` only (it flattens it) — use flat task fields for every other agent. - **BYOK and guardrails are trust fences.** `402 byok_required`, `403 model_not_allowed`/`content_blocked`, `429 spend_cap_exceeded` — never engineer around them; surface and let the human/org decide. ## Related skills - `plungeai-discovery` — find agents/tools/models/skills live, never from memory. - `plungeai-agents` — execute a single agent (`model`/`provider` overrides on `plungeai_execute_agent` / `POST /v1/agents/{id}/execute`). - `plungeai-tools-connectors` — typed tool execution and contracts. - `plungeai-workflows` — steer `model`/`provider` per task or per harness mission in CNL YAML. - `plungeai-api-setup` / `plungeai-mcp-setup` — connecting an `ozk_`/`sk-ocean-` key in the first place. ## Reference pages <CardGroup cols={2}> <Card title="Models plane — /v1/chat/completions, /v1/embeddings, /v1/models" icon="file-text" href="/skills/plungeai-models/references/money-plane"> The OpenAI-compatible surface ("money plane"). </Card> <Card title="Models — provider factory inside runs, money plane for your code" icon="file-text" href="/skills/plungeai-models/references/provider-factory"> PlungeAI touches models in two distinct places. Keep them apart: </Card> </CardGroup> # Models plane — /v1/chat/completions, /v1/embeddings, /v1/models Source: https://docs-preview.plungeai.com/skills/plungeai-models/references/money-plane <!-- sources-of-truth: orchestration/api-gateway/openapi.ts, docs/ONE-API-DEVELOPER-GUIDE-2.0.md, inference/gateway/src/errors.ts, inference/gateway/src/routing/select.ts, inference/gateway/src/metering/response-cache.ts, apps/ocean-dashboard/src/nav.ts, apps/ocean-dashboard/src/components/sections/one-api/KeysTab.tsx, apps/ocean-dashboard/src/components/sections/one-api/CatalogTab.tsx | last-synced: 2026-09-24 (re-verified: error codes against errors.ts, 30s outage exclusion against select.ts, 60-86400s cache TTL clamp against response-cache.ts — all match; fixed stale UI labels — sk-ocean- keys and BYOK provider keys live under Dashboard → One API → Keys/Catalog, not "Ocean Dashboard → API keys" or "Settings → Integrations", which do not exist in nav.ts) --> The OpenAI-compatible surface ("money plane"). Auth is a **different key** from the rest of the API: `Authorization: Bearer sk-ocean-YOUR_KEY` (from Ocean Dashboard → One API → Keys, "Model gateway keys" panel). Errors use the OpenAI error shape `{"error":{"message","type","code","request_id"}}`. ## Drop-in base_url swap Point the OpenAI SDK you already use at the base URL. That is the entire integration: **Python** ```python from openai import OpenAI client = OpenAI(base_url="https://api.plungeai.com/v1", api_key="sk-ocean-YOUR_KEY") r = client.chat.completions.create( model="anthropic/claude-sonnet-5", messages=[{"role": "user", "content": "Hello"}]) print(r.choices[0].message.content) ``` **TypeScript** ```ts import OpenAI from 'openai' const client = new OpenAI({ baseURL: 'https://api.plungeai.com/v1', apiKey: process.env.PLUNGEAI_INFERENCE_KEY, // sk-ocean-YOUR_KEY }) const r = await client.chat.completions.create({ model: 'anthropic/claude-sonnet-5', messages: [{ role: 'user', content: 'Hello' }], }) ``` **curl** ```bash curl -s https://api.plungeai.com/v1/chat/completions \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"anthropic/claude-sonnet-5","messages":[{"role":"user","content":"Hello"}]}' ``` ```json { "id": "chatcmpl-...", "object": "chat.completion", "model": "anthropic/claude-sonnet-5", "choices": [{ "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help?" }, "finish_reason": "stop" }], "usage": { "prompt_tokens": 8, "completion_tokens": 9, "total_tokens": 17 } } ``` Model slugs are `provider/model`. Get the live priced list from `GET /v1/models` — never hardcode a slug list from memory. The enforcement is **404 `model_not_found`**: an unknown slug fails, so populate model choices from `GET /v1/models` at runtime. Streaming (`"stream": true` → `text/event-stream`), any other OpenAI-compatible field (`tools`, `response_format`, `top_p`, …) passes through untouched. ## POST /v1/chat/completions — request fields beyond OpenAI's | Field | Type | Semantics | |---|---|---| | `model` | string | One slug, or `@preset/<slug>`. Ignored if `models` is set | | `models` | string[] | **Ordered fallback list** — tried in order; first success serves | | `sort` | `"price"` \| `"latency"` \| `"throughput"` | Reorders `models[]` before the first attempt. Providers with no latency/throughput history sort last | | `temperature` | number | Exactly `0` makes the request response-cache eligible | ### Routing & failover (`models[]`) ```bash curl -s https://api.plungeai.com/v1/chat/completions \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" -H "Content-Type: application/json" \ -d '{"models":["anthropic/claude-sonnet-5","openai/gpt-5"], "sort":"price", "messages":[{"role":"user","content":"Hello"}]}' ``` - Each candidate gets **one retry** (2 attempts total) on `429`/`5xx`/network error; backoff honors a short `Retry-After` (capped 2s) or flat 250ms. - Exhausting a candidate excludes its **provider** for **30 seconds** and moves to the next; a still-excluded candidate shows `"reason":"outage_excluded"` in the logged `route_attempts` (not re-probed). - A non-429 `4xx` (your request is malformed) is **not** retried and **not** failed over — the next candidate would fail identically. - **Honest billing**: the response's `model` field is the slug that **actually served** the request — possibly a fallback, not what you asked for first. Bill, log, and display on the response `model`, never on the requested one. - **Streaming caveat**: failover works identically for `stream:true` — the decision happens on the response status before any bytes are forwarded — but a stream that dies mid-flight is not retried. The `model` field inside SSE chunks reflects the serving upstream natively; billing still uses the honest slug. ## Presets — `@preset/<slug>` A stored model+routing+params bundle, addressed via the `model` field: ```bash curl -s https://api.plungeai.com/v1/chat/completions \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" -H "Content-Type: application/json" \ -d '{"model":"@preset/fast","messages":[{"role":"user","content":"Hello"}]}' ``` Request-explicit fields **always override** the preset — it only fills gaps. Unknown/inactive slug → **404 `preset_not_found`**. Presets are administered platform-side; ask your admin which exist for your org. ## Response cache (opt-in, per org) - Eligible only when `temperature: 0` is **explicit** and `stream` is not true. - Cache key = hash of the **full request body** — any differing field misses. - Header `x-cache: miss` (stored for next time) / `x-cache: hit` (served from cache, **never billed**, same response id). Header absent entirely when the org has caching off or the request wasn't eligible. - TTL is per-org, clamped 60s–86400s. ## Guardrails & pricing (BYOK-or-billed) Per-org/per-key policy — spend caps, provider/model allow-lists, content-blocking, BYOK requirements — enforced **before** cache lookup and before any money moves. Strictest wins when org and key policies overlap. Pricing: platform-billed by default (provider cost + org markup). Connect your own provider key (BYOK, Dashboard → One API → Catalog → "BYOK provider keys") and requests to that provider route through it for a small routing fee instead. Org policy can *require* BYOK per provider. Trial orgs are metered but never charged. ## Error catalogue | Status | Code | Meaning | Handling | |---|---|---|---| | 400 | `invalid_json` | Request body is not valid JSON | Fix the body | | 401 | `invalid_api_key` | Missing/invalid `sk-ocean-` key | Fix the key | | 402 | `insufficient_balance` | Credit balance at $0 — the first error every platform-billed org hits | Surface: top up (the message carries the URL) | | 402 | `byok_required` | Provider requires your own connected key on this plan | Surface: connect key in Dashboard → One API → Catalog, or change plan | | 403 | `model_not_allowed` | All routing candidates excluded by allow-list | Surface; pick an allowed model (see `GET /v1/models`) | | 403 | `content_blocked` | Prompt matched a guardrail regex (pattern never echoed) | Surface; do not retry variants to probe the filter | | 404 | `model_not_found` | Unknown model slug | Re-pick from `GET /v1/models`; never hardcode slugs | | 404 | `preset_not_found` | `@preset/<slug>` unknown or inactive | Fix the slug | | 429 | `rate_limit_exceeded` | Atomic per-key limiter — **no `Retry-After` on this path** | Fixed short backoff (~1s), then retry | | 429 | `insufficient_quota` | Monthly spend limit reached (type `rate_limit_error`) — distinct from both other 429s | Surface — resets with the billing period; do NOT retry-loop | | 429 | `spend_cap_exceeded` | Guardrail cap reached | Surface — a policy, not a transient; do NOT retry-loop | | varies | `upstream_error` | Provider failure — the provider's own status is passed through (type `api_error`) | One retry with backoff (routing already retried/failed over) | | 500 | `internal_error` | Gateway error | One retry with backoff | | 503 | `money_plane_unavailable` | Inference gateway not bound on this tier | Surface; wrong tier/deployment | Example 402: ```json {"error":{"message":"This provider requires your own API key on your plan — connect it in Settings → Integrations, or upgrade to platform-billed usage","type":"byok_required","code":"byok_required","request_id":"00000000-0000-4000-8000-000000000004"}} ``` ## POST /v1/embeddings Same auth, same guardrail enforcement as chat completions. ```bash curl -s https://api.plungeai.com/v1/embeddings \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" -H "Content-Type: application/json" \ -d '{"model":"openai/text-embedding-3-small","input":["hello world"]}' ``` ```json { "object": "list", "data": [{ "object": "embedding", "index": 0, "embedding": [0.0123, -0.0456, "..."] }], "model": "openai/text-embedding-3-small", "usage": { "prompt_tokens": 2, "total_tokens": 2 } } ``` `input` is a string or an array of strings. ## GET /v1/models — the priced catalog The live list routing candidates are drawn from — ids, pricing, provider. ```bash curl -s https://api.plungeai.com/v1/models \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" ``` ```json { "object": "list", "data": [ { "id": "anthropic/claude-sonnet-5", "provider": "anthropic", "pricing": { "input": "...", "output": "..." } }, { "id": "openai/gpt-5", "provider": "openai", "pricing": { "...": "..." } } ] } ``` Generated code that lets users pick a model should populate the choice from this endpoint at runtime, not from a baked-in list. # Models — provider factory inside runs, money plane for your code Source: https://docs-preview.plungeai.com/skills/plungeai-models/references/provider-factory <!-- sources-of-truth: core/core-provider/CLAUDE.md, docs/architecture.md, orchestration/api-gateway/openapi.ts, orchestration/cnl-engine/schema-types.ts | last-synced: 2026-09-24 (re-verified: 32 provider dirs + pattern-based detection + 3-turn auto-continue cap against core-provider/CLAUDE.md, InlineMission model/provider/effort + followup provider/model/temperature against schema-types.ts — all match; added the missing caveat that an explicit maxTokens disables auto-continuation entirely, per core-provider/CLAUDE.md line 111) --> PlungeAI touches models in two distinct places. Keep them apart: 1. **Inside platform runs** — agents, workflows, and missions resolve models through the platform's **provider factory**: a fleet of per-provider Workers behind one selection layer. You steer it with `model`/`provider` fields on tasks and missions. 2. **The money plane** — an OpenAI-compatible inference API at `https://api.plungeai.com` (`/v1/chat/completions`, `/v1/embeddings`, `/v1/models`) for YOUR code, with routing intelligence on top. Discovery-first applies doubly here: model catalogs churn weekly. `GET /v1/models` is the priced, live catalog — never hardcode a model list in generated code. ## 1. Models inside platform runs (provider factory) Every LLM-capable agent resolves its model through the central provider layer — one Worker per provider (Anthropic, OpenAI, Gemini, Groq, xAI, OpenRouter, Cerebras, Cohere, Mistral, Together, Fireworks, Perplexity, Bedrock, Vertex, and more; the fleet grows — treat any list as illustrative). Each provider Worker: - serves streaming (SSE) and non-streaming completions behind the same interface; - detects model capabilities by **pattern**, not hardcoded lists — new models of a known family work without platform changes (e.g. a new `gpt-5.x` or `o<n>` routes as a reasoning model automatically); - **auto-continues on truncation**: when a completion stops at the output-token limit, the provider re-issues with a continue turn (capped at 3 extra turns) so workflow steps do not silently end mid-sentence — but only when `maxTokens` is left unset. An **explicit** `maxTokens` is a hard cap: it disables auto-continuation and the answer stops at the budget with `finish_reason: length`; - records token usage per task so every run is priced post-hoc — this is where the cost numbers in the `plungeai-results-traces` skill come from. ### Steering model choice in YAML ```yaml # On a plain task — flat fields on the task, passed through to the agent - type: task id: analyze agent: llm-agent prompt: "…" model: claude-sonnet-5 maxTokens: 4096 # On a harness mission (mission-level override) - type: harness goal: "…" mission: | You are a careful researcher. model: claude-sonnet-5 provider: anthropic effort: standard # Follow-up behavior of a saved workflow followup: provider: anthropic # openai | groq | anthropic | gemini model: claude-sonnet-4-5 temperature: 0.7 ``` Flat task fields are the platform spec (`persona`/`model`/`maxTokens` etc. pass through). A nested `config: {model, maxTokens}` block is tolerated by `llm-agent` only, which flattens it — do not rely on nesting for other agents. Omit `model` and the agent/provider default applies — usually the right call. Override only when the job demands a specific capability tier (reasoning depth, speed, cost). Provider-specific extras (extended thinking, reasoning effort, search grounding) pass through the same config fields per the agent's card. ## 2. The money plane (OpenAI-compatible, with routing) Auth: **`sk-ocean-` keys** (not `ozk_`). Any OpenAI-compatible client works by pointing its base URL at `https://api.plungeai.com/v1`. ```bash curl -s https://api.plungeai.com/v1/chat/completions \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" -H "Content-Type: application/json" \ -d '{ "model": "anthropic/claude-sonnet-5", "messages": [{"role": "user", "content": "Say hello"}] }' ``` Model slugs are `provider/model` (e.g. `anthropic/claude-sonnet-5`). The response is standard OpenAI shape — with one honest twist: > **`model` in the response is the slug that ACTUALLY served the request.** After a > failover it may differ from what you asked for. Bill and log on the response value. ### Routing intelligence (what you get beyond a raw proxy) ```json { "models": ["anthropic/claude-sonnet-5", "<second choice from /v1/models>", "<third choice from /v1/models>"], "sort": "latency", "messages": [{"role": "user", "content": "…"}] } ``` (Fallback slugs must come from `GET /v1/models` — discover, don't assume.) - **`models[]`** — ordered fallback candidates (alternative to `model`). One retry per candidate on 429/5xx/network, then failover to the next; a provider that just failed is excluded for 30 s. - **`sort`** — `price` | `latency` | `throughput` reorders `models[]` from rolling provider stats before the first attempt (no history sorts last). - **`@preset/<slug>`** as `model` — expands a stored model+routing+params bundle; request-explicit fields still override. - **Response cache** (opt-in per org): exact-match, only for `temperature: 0` non-streaming requests; `x-cache: hit|miss` header when eligible. - **Guardrails** per org/key: spend caps, model allow-lists, content filtering, BYOK gates — enforced server-side on chat AND embeddings. - `stream: true` → `text/event-stream`. ### Embeddings and catalog ```bash curl -s https://api.plungeai.com/v1/embeddings \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" -H "Content-Type: application/json" \ -d '{"model": "openai/text-embedding-3-small", "input": ["hello", "world"]}' curl -s https://api.plungeai.com/v1/models \ -H "Authorization: Bearer sk-ocean-YOUR_KEY" # → {object: "list", data: [{id, pricing, provider}, …]} — the priced catalog # routing candidates are drawn from. Discover, don't assume. ``` ### Money-plane errors — each names its fix | Status | Code | Meaning / action | |---|---|---| | 401 | invalid key | Wrong or missing `sk-ocean-` key | | 402 | `byok_required` | This provider needs the org's own connected key on this plan — connect it in Studio | | 403 | `model_not_allowed` | All routing candidates excluded by an allow-list — pick an allowed model | | 403 | `content_blocked` | Prompt matched a guardrail filter — do not rephrase-to-evade; surface to the user | | 404 | `preset_not_found` | `@preset/<slug>` missing or inactive | | 429 | `rate_limit_exceeded` / `spend_cap_exceeded` | Back off / the org's cap is reached — raising it is a human decision | | 503 | `money_plane_unavailable` | Inference not staged on this tier | Guardrail refusals (402/403/429-cap) are **trust fences**: surface them, never engineer around them. ## Choosing between the two surfaces | Job | Surface | |---|---| | A workflow/mission step needs an LLM | Inside the run: `llm-agent` (or a domain agent) with optional `model` override | | Your application needs chat/embeddings directly | Money plane | | You want fallback across providers without writing retry logic | Money plane `models[]` + `sort` | | You need the run traced/priced with the rest of a pipeline | Inside the run — platform observability covers it end-to-end | Both surfaces echo `x-request-id` and accept `x-trace-id` for correlation — see the `plungeai-results-traces` skill. # plungeai-platform Source: https://docs-preview.plungeai.com/skills/plungeai-platform THE PlungeAI (Ocean) platform capability map: a growing live registry of agents and structured tools, CNL multi-agent workflows, bounded harness missions, injectable skills/plugins/experts/personas, model routing with an OpenAI-compatible inference API, cron scheduling, per-user long-term memory, and full run observability — how the five layers fit together and which capability skill covers which job. Use when the user asks "what can PlungeAI do", "which PlungeAI capability/agent/tool for X", wants an end-to-end mental model of the platform, hits a trust fence (`403 refused` / `needs_approval` / `409`) and needs the doctrine, or is planning multi-step work and needs to pick between a single agent call, a CNL workflow, and a harness mission. For which door (MCP/REST/CLI/Studio) to use, load `choose-your-plungeai-door` first; each capability's own deep-dive skill (named below) covers its exact tools/params. [Download zip](https://skills.plungeai.com/plungeai-platform.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-platform/SKILL.md) PlungeAI (internally "Ocean") is a Cloudflare-native agent runtime: every agent, tool, and workflow runs as a deployed edge service, connected by RPC. You do not install or host anything — you operate the live platform through one of four doors (MCP, One API, Ocean CLI, Ocean Studio — see `choose-your-plungeai-door`) and compose its capabilities. There is no local mode: everything you execute runs on the deployed platform, and everything you read (catalogs, contracts, results) is live. The platform is **discovery-first by design**: the agent catalog, tool contracts, model list, and workflow inventory change without notice. Never assert what exists from memory — look it up (see "Discovery first" below). "90+ agents and growing" is flavor; the live catalog is the fact. ## Connect MCP (Claude Code shown; other clients use the equivalent `mcpServers` JSON — install page: `https://mcp.plungeai.com/install`; full setup: `plungeai-mcp-setup`): ```bash claude mcp add --transport http plungeai https://mcp.plungeai.com/v1 \ --header "Authorization: Bearer ozk_YOUR_KEY" ``` One API (same `ozk_` key, `Authorization: Bearer` or `X-API-Key`; full setup: `plungeai-api-setup`): ```bash curl -s https://api.plungeai.com/v1/agents?limit=3 \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` Keys are self-service `ozk_` keys from **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`). `ozk_` keys authenticate the execution planes; the model-inference money plane (`/v1/chat/completions`, `/v1/embeddings`, `/v1/models`) uses `sk-ocean-` keys instead — see `plungeai-models`. Rate limits by tier: free 30/min, pro 100/min (default), enterprise 300/min (as of last sync — the tier table at `GET https://api.plungeai.com/docs` is authoritative; `plungeai_whoami` shows your live window). A plain-text platform summary for any LLM lives at `https://mcp.plungeai.com/llms.txt`. ## Verify Before doing real work, prove the connection and identity once: - **MCP:** call `plungeai_whoami` — returns the identity card: user id, tier, key label, rate-limit window. If it fails, the key or transport is wrong; fix that before anything else. - **One API:** `curl -s https://api.plungeai.com/health` (no auth) proves the router is up; an authenticated `GET /v1/agents?limit=1` proves the key. ## How the platform fits together Five layers, bottom to top — useful when deciding where a problem lives: | Layer | What it does | You touch it via | |---|---|---| | **Runtime** | Agents execute; providers serve models; memory stores state. Every agent is a deployed edge service with one uniform task interface | `plungeai-agents`, `plungeai-tools-connectors`, `plungeai-models`, `plungeai-memory` | | **Orchestration** | The CNL engine runs workflows as DAGs of agent calls (parallel/sequential/…); the scheduler fires them on cron | `plungeai-workflows`, `plungeai-scheduling` | | **Harness** | Mission-bounded autonomous runs: tool fence, iteration cap, recursion guard, memory recall | `plungeai-missions` | | **Capability injection** | Skills, plugins, experts, personas, backgrounds, MCP servers injected per run into one loop agent | `plungeai-skills-plugins` | | **Product** | Ocean Studio (build), dashboards (operate), branded runner apps (use) | Studio, for humans | Two properties fall out of this architecture and explain most behavior you will observe: internal calls are RPC between deployed Workers (which is why parallel fan-out is essentially free — see `plungeai-workflows`), and every result is stored under `(workflow_id, task_id)` (which is why every execution returns redeemable pointers — see `plungeai-memory`). ## Capability map One skill per capability. This table is the router — load the skill before working in that area. | Capability | What it gives you | Skill | |---|---|---| | **Discovery** | Find agents/tools/models/skills/connectors/templates on the live registry — never from memory | `plungeai-discovery` | | **Agents** | Registry of building-block agents (search, LLM, documents, finance, social, …) — discover and execute one | `plungeai-agents` | | **Tools & connectors** | Structured tool-agents with typed contracts (JSON Schema params, operations, approval gates, connected accounts) | `plungeai-tools-connectors` | | **Workflows** | CNL YAML multi-agent orchestration: parallel/sequential/batch/debate/… pipelines | `plungeai-workflows` | | **Models** | Provider factory inside runs + OpenAI-compatible inference API with routing/fallback | `plungeai-models` | | **Skills / Plugins / Experts / Personas** | Injectable instruction packs, Claude-Code-format plugin bundles, voice/domain expertise, standing context | `plungeai-skills-plugins` | | **Missions** | Bounded autonomous agent runs: goal, tool fence, iteration cap, success criteria | `plungeai-missions` | | **Scheduling** | Cron jobs that run workflows/agents/missions unattended | `plungeai-scheduling` | | **Campaigns** | Ledgered, claim-based batch work across many rows (the data-table campaign primitive) | `plungeai-campaigns` | | **Memory** | Run-data exchange (SharedMemory) + per-user long-term memory | `plungeai-memory` | | **Results & traces** | Live SSE events, execution history, persisted traces, cost | `plungeai-results-traces` | | **Chat** | Persistent platform chat with sessions (`plungeai_chat` — send/new/list_sessions/history); conversations appear in Studio and the CLI | `plungeai-mcp-setup` | ## Which capability for which job - **One-shot capability call** ("search the web", "convert this PDF"): a single agent. Prompt-driven → `plungeai_execute_agent`; structured (has a parameters table) → `plungeai_get_tool_contract` then `plungeai_execute_tool`. → `plungeai-agents`, `plungeai-tools-connectors` - **Multi-step pipeline with known steps** ("research A, B, C in parallel, then synthesize"): a CNL workflow. → `plungeai-workflows` - **Open-ended goal needing judgment** ("investigate X and produce a memo, use whatever tools you need"): ONE harness mission, not many small tasks. → `plungeai-missions` - **Behavior/knowledge an agent should carry into a run** (style guide, domain method, company context): skills, plugins, experts, personas, backgrounds. → `plungeai-skills-plugins` - **Raw LLM inference in your own code** (chat/embeddings, model fallback): the One API money plane. → `plungeai-models` - **"Every morning / every hour" anything**: schedule it. → `plungeai-scheduling` - **Batch work over many rows with claims/leases** (a "campaign"): → `plungeai-campaigns` - **"Remember this" / "what did we learn last run"**: long-term memory. → `plungeai-memory` - **"Why did that run fail / how long / what did it cost"**: observability. → `plungeai-results-traces` ## Discovery first (non-negotiable) Catalogs are live and execution refuses stale ids. Always: 1. **Agents:** `plungeai_list_agents {search: "<capability in plain words>"}` — a hybrid semantic + keyword search; describe the job, trust the ranking. REST: `GET /v1/agents`, `GET /v1/discovery/search?q=…`. Take ids verbatim (kebab-case, e.g. `brave-agent`, `exa-agent`) from results only. 2. **Injectable capability ids** (skills, experts, personas, models, workflows, connectors): the same tool with a `kind` filter — `plungeai_list_agents {kind: "skills" | "experts" | "personas" | "models" | "workflows" | "connectors", search: "…"}`. REST: `GET /v1/discovery/search?kind=…`. A typo'd injectable id silently degrades to a warning (`plungeai-skills-plugins`) — look ids up before declaring them. 3. **Tool shapes:** `plungeai_get_tool_contract {agent_id}` or `GET /v1/tools/{id}` before the first call to an unfamiliar structured agent — the contract IS the docs. 4. **Routes:** `GET /v1/openapi.json` — never invent One API paths. 5. **Models:** `GET /v1/models` — the priced catalog routing draws from (this one endpoint takes an `sk-ocean-` key, not `ozk_` — see `plungeai-models`). 6. **The user's own inventory:** `plungeai_list_workflows` (in user parlance, "my agents" means their saved workflows — not the registry). Full discovery mechanics (search params, cards, contracts, templates) — `plungeai-discovery`. ## Trust fences and structured outcomes The platform answers with structured outcomes, never raw errors. Respect them: - **Over MCP the outcome is an envelope, not an HTTP error**: every tool answers HTTP 200 with a status of `ok`, `needs_input`, `needs_connection`, `needs_api_key`, `needs_approval`, `unavailable`, or `error` (there is no `refused` MCP status — fences spell as HTTP codes only on the One API). - **`403 refused`** (One API): a fence blocked the call — gated or money operation attempted unattended. Surface it to the user. **Never retry**; a fence is a policy, not a flake. - **`409 approval_required`** / **`needs_approval` outcome + a paused run (`⏸ AWAITING USER APPROVAL`)**: a human must decide. Relay the approval block verbatim, wait for the user's explicit answer, then `plungeai_continue` (`approve: true` ONLY after they said yes; their refusal or change of course goes in `message`). Never approve on your own. - **`needs_input`** (or `422 invalid_params`): the response names the missing/invalid fields and carries the schema — fix exactly those, then retry once. - **`needs_connection` / `needs_api_key`**: the acting user must connect a credential in the platform apps (Studio). Tell them exactly what to connect; retry after. - **`unavailable`**: the outcome lists live alternatives — pick one or re-discover. Same doctrine everywhere: follow the remediation in the outcome; never blind-retry the identical call. ## A complete first session (MCP) The canonical shape of operating the platform, end to end — adapt the middle to the job: ``` 1. plungeai_whoami → identity card (proves key, tier, rate window) 2. plungeai_list_agents {search: "web search", user_request: "research solid-state battery commercialization for me"} → ranked cards; pick e.g. brave-agent, exa-agent (ids verbatim) 3. plungeai_execute_workflow { user_request: "research solid-state battery commercialization for me", workflow_yaml: " name: quick research tasks: - type: parallel id: research subtasks: - { type: task, id: a, agent: brave-agent, query: \"{input}\" } - { type: task, id: b, agent: exa-agent, query: \"{input}\" } - type: task id: brief agent: llm-agent prompt: \"Write a sourced brief on: {input}\" ", input: "solid-state battery commercialization"} → result (final markdown — relay verbatim) For >3 min jobs: mode: "async" → plungeai_get_workflow_status → plungeai_get_result 4. Output is right → plungeai_workflow {action: "create", name, yaml, description} → saved, synced live to Studio and peer apps 5. plungeai_schedule {action: "create", job_type: "workflow", target: "<saved id>", schedule: "0 7 * * *"} → runs every morning; verify once with {action: "run_now"} ``` Steps 2-3 change per job (single agent call, tool contract + typed execution, or a harness mission via `plungeai_run_mission`) — the frame (verify → discover → test → save → schedule) does not. ## Operating rules - **Every `plungeai_*` call also takes `user_request`** — pass the user's ask verbatim, in their own words (the platform uses it for routing and support diagnostics; arguments alone lose the intent). - **Agent ids only from a live search.** Unknown or inactive ids are refused at execution time. - **Async for long runs.** Anything over ~3 minutes: `mode: "async"` (on `plungeai_execute_workflow` / `plungeai_execute_tool` / `plungeai_run_mission` — `plungeai_execute_agent` has none; wrap it in a one-task workflow) → poll `plungeai_get_workflow_status` → fetch with `plungeai_get_result` when completed. - **Results are final, user-ready markdown.** Present them verbatim and in full — do not re-format, shorten, or re-type them as your own prose. - **Test before saving.** Run ad-hoc (`plungeai_execute_workflow {workflow_yaml}`) and read the actual output before `plungeai_workflow {action: "create"}`. - **Idempotency:** payment-, messaging-, and automation-class agents may duplicate side effects on re-runs. Do not re-fire a call that may already have acted; check execution status first. ## Common pitfalls | Pitfall | Reality | |---|---| | Using an agent id from memory or an old example | Catalog is live, active-only; execution refuses stale ids. Search first, always | | "Show me my agents" answered with the registry | Users mean their saved workflows → `plungeai_list_workflows` | | Prose prompt sent to a structured tool-agent | Cards with a Parameters table take typed `params` via the contract door (`plungeai-tools-connectors`) | | Retrying a `403`/`refused` or self-approving a `409`/`⏸` | Fences are policy. Surface, get the human decision, `plungeai_continue` | | Decomposing an open-ended goal into many guessed tasks | One `type: harness` mission with a fence beats a brittle guessed pipeline (`plungeai-missions`) | | Summarizing platform output "helpfully" | Outputs are final user-ready markdown — relay verbatim and in full | | Blocking on a long sync call | `mode: "async"` + status polling exists for exactly this | | Baking dates into scheduled workflows | Date tokens (`{week_start}`, …) roll automatically (`plungeai-scheduling`) | | Storing context as long-term memory that belongs in a background/skill | Memory is learned per-user state; authored shared context goes in backgrounds/skills (`plungeai-memory`) | | Inventing One API routes or model names in generated code | `GET /v1/openapi.json` and `GET /v1/models` are the only authorities | ## Related skills - `choose-your-plungeai-door` — which door (MCP/REST/CLI/Studio) for which job. - `plungeai-mcp-setup` / `plungeai-api-setup` / `plungeai-cli-setup` — connect and verify a client. - Every capability in the map above has its own deep-dive skill by the same name. - `plungeai-in-<tool>` — wiring a specific coding tool's agent to PlungeAI over MCP. # plungeai-results-traces Source: https://docs-preview.plungeai.com/skills/plungeai-results-traces Debug and observe PlungeAI runs: live SSE events, plungeai_get_workflow_status / plungeai_executions history, persisted GET /v1/traces/{id} spans and gateway request cost, the HITL conversation loop (plungeai_continue/plungeai_followup/plungeai_chat), and outbound MCP door runs (POST /v1/mcp/runs). Use when a run seems hung, failed, or expensive, when the user wants to correlate calls with x-trace-id, or when resuming a paused ⏸ run. For a run's actual output content use `plungeai-memory`'s SharedMemory section; for authoring the workflow being observed use `plungeai-workflows`. [Download zip](https://skills.plungeai.com/plungeai-results-traces.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-results-traces/SKILL.md) Every execution is observable at four altitudes: live events while it runs, a status/history record after, a persisted span-level trace, and the gateway's own request log with cost. Read them in this order instead of re-running the workload to "see what happens." ## Prerequisites - A self-service `ozk_` API key from **Dashboard → One API → Keys** (https://dashboard.plungeai.com), or an MCP client connected to `https://mcp.plungeai.com/v1`. - Always capture the ids a run gives you: `workflow_id`/`execution_id`, `request_id`, and your own `x-trace-id`. Without them you are grepping timestamps. ## Correlation ids — wire them in from the start Every One API response echoes a server-minted `x-request-id`; send your own `x-trace-id` header to correlate a whole multi-call operation. If you never sent one, the trace id IS that call's `x-request-id` — still traceable: ```bash curl -s -X POST https://api.plungeai.com/v1/agents/llm-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -H "x-trace-id: my-batch-2026-08-27-001" -d '{"prompt": "Say: traced"}' curl -s https://api.plungeai.com/v1/traces/my-batch-2026-08-27-001 \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` An unknown/lagging trace id returns `200` with empty arrays, never `404` — poll until `spans` is non-empty (with a cap), don't wait for a 404. ## The debugging playbook 1. **Run seems hung** → `plungeai_get_workflow_status` (self-heals stuck rows; may return a `continuation` block — the run is waiting on a human, not hung). 2. **Run failed** → status `error_message` → the trace's failing span (`status`, `agent`, `duration_ms`). 3. **Output is thin** → execution summary `failed_branches[]` and `tasks_skipped`. 4. **Slow** → per-task durations from SSE events/spans; a staircase against one destination means queueing there, not in the engine. 5. **Expensive** → trace `gateway_requests[].cost_usd` by route. 6. **Instructions seemingly ignored** → the run's own warnings (capability ids that degraded — `plungeai-skills-plugins`). Full playbook, execution-summary fields, and quality signals: [`references/observability.md`](/skills/plungeai-results-traces/references/observability). Full `GET /v1/traces/{id}` shape and error rules: [`references/traces.md`](/skills/plungeai-results-traces/references/traces). ## The ⏸ human-in-the-loop loop A run pauses (never dies) on an `ask_user` question or an approval gate, surfaced as `continuation` on `plungeai_get_workflow_status`. Relay the block verbatim, wait for the human's words, then: - `plungeai_continue {execution_id, approve: true}` — ONLY after an explicit yes. - `plungeai_continue {execution_id, message: "<their words>"}` — anything else. Never approve on your own, never rephrase the pending action, never retry around a pause. Once a run is COMPLETE, use `plungeai_followup {execution_id, prompt}` instead — `continue` on a finished run redirects you there. Free-standing chat with no run in sight is `plungeai_chat`. Full parameter tables and failure messages: [`references/conversation.md`](/skills/plungeai-results-traces/references/conversation). ## Outbound MCP door runs Separately from the platform's own inbound MCP tools, you can open a metered run against third-party MCP servers: `POST /v1/mcp/runs {server_ids: [...]}` → call namespaced tools (`mcp__<server>__<tool>`) → `DELETE` to close. Runs expire after 30 idle minutes. Full lifecycle, error shapes, and a working TypeScript pattern: [`references/mcp-runs.md`](/skills/plungeai-results-traces/references/mcp-runs). ## Gotchas - Per-task duration is measured from SERVER timestamps in the SSE stream — never time a run from your own clock around the request. - `payload_inline` on a trace span is guard-scanned and capped at 1 KB; larger payloads sit behind `payload_ref` (not fetchable through this API). - A scheduler run id is not directly resolvable by `plungeai_get_workflow_status` / `plungeai_get_result` — go through `plungeai_schedule {action: "runs"}` first (`plungeai-scheduling`). - Full `plungeai_get_workflow_status` / `plungeai_executions` parameter and return contracts live in `plungeai-workflows` (`references/mcp.md`) — this skill covers what to do with them once you have a run's ids. ## Related skills - `plungeai-workflows` — full `plungeai_get_workflow_status` / `plungeai_executions` contracts, and authoring the workflow being observed. - `plungeai-missions` — mission-specific pause/resume and iteration-cap semantics. - `plungeai-scheduling` — a scheduled job's own run ledger. - `plungeai-memory` — SharedMemory (`plungeai_get_result`), a run's actual output. - `plungeai-skills-plugins` — the capability-resolution warnings this playbook checks. ## Reference - [`references/observability.md`](/skills/plungeai-results-traces/references/observability) — correlation ids, SSE event order, execution summary, the debugging playbook, quality signals. - [`references/traces.md`](/skills/plungeai-results-traces/references/traces) — full `GET /v1/traces/{id}` route detail. - [`references/conversation.md`](/skills/plungeai-results-traces/references/conversation) — `plungeai_continue` / `plungeai_followup` / `plungeai_chat` and the ⏸ HITL protocol. - [`references/mcp-runs.md`](/skills/plungeai-results-traces/references/mcp-runs) — outbound MCP door: open/list/call/close a run. ## Reference pages <CardGroup cols={2}> <Card title="Conversation — chat, followup, continue (and the ⏸ HITL loop)" icon="file-text" href="/skills/plungeai-results-traces/references/conversation"> Three distinct conversation surfaces — pick by what the user is doing: </Card> <Card title="MCP plane — /v1/mcp" icon="file-text" href="/skills/plungeai-results-traces/references/mcp-runs"> Two directions in one plane: </Card> <Card title="Observability — watching, debugging, and pricing platform runs" icon="file-text" href="/skills/plungeai-results-traces/references/observability"> Every execution on PlungeAI is observable at four altitudes: live events while it runs, an execution record after it finishes, a persisted span-level trace… </Card> <Card title="Traces — GET /v1/traces/{id}" icon="file-text" href="/skills/plungeai-results-traces/references/traces"> The observability plane: one id follows a request across every internal hop. </Card> </CardGroup> # Conversation — chat, followup, continue (and the ⏸ HITL loop) Source: https://docs-preview.plungeai.com/skills/plungeai-results-traces/references/conversation <!-- sources-of-truth: orchestration/mcp-gateway/tools.ts, orchestration/mcp-gateway/conversation.ts, orchestration/mcp-gateway/chat.ts, orchestration/mcp-gateway/server.ts | last-synced: 2026-09-24 --> Three distinct conversation surfaces — pick by what the user is doing: | Surface | Anchored to | Use when | |---|---|---| | `plungeai_chat` | A standing conversation (its own `conversation_id`) | Open-ended chat with the platform assistant, across days. | | `plungeai_followup` | A COMPLETED execution (`execution_id`) | "Ask more about that run" — the run's result is the context. | | `plungeai_continue` | A PAUSED execution (`execution_id`) | The run stopped with a ⏸ block — a question or a pending approval. | The execution id doubles as the conversation session id: every follow-up and continue turn on a run lands in that run's conversation thread, which `plungeai_get_result` and `plungeai_executions {action: "conversation"}` render in full (Studio shows the same thread). --- ## The ⏸ HITL loop (read this first) A conversational or gated agent stops in one of two states, appended to the run's result and surfaced by `plungeai_get_workflow_status` as `structuredContent.continuation`: ``` ⏸ AWAITING USER APPROVAL: <action summary> (<price>) Ask the user to confirm, then call plungeai_continue with execution_id "<id>" and approve: true (or message: "<their words>"). ``` ``` ⏸ AWAITING USER: <question> Relay this to the user, then call plungeai_continue with execution_id "<id>" and message: "<their answer>". ``` In the status tool's machine mirror these map to `continuation.status: "needs_approval"` and `"question"` respectively. **The protocol, exactly:** 1. Relay the block to the user VERBATIM (it is theirs, not yours) and ask them to decide ("Approve this action? yes/no"). 2. Wait for their words. 3. `plungeai_continue {execution_id, approve: true}` ONLY for an explicit yes. Anything else — an answer, a denial, a change of course — goes as `message: "<their words>"`. 4. The reply either ends with another ⏸ block (loop again) or with `✅ Conversation resolved (no further input needed)`. Approval fences are trust fences: never approve on your own, never rephrase the pending action, never "retry" around a pause. Async runs surface pending approvals via `plungeai_get_workflow_status` and `plungeai_get_result` — the same protocol applies from there. --- ## plungeai_continue **Purpose:** resume a paused conversation — answer the agent's question or deliver the user's approval decision. **Parameters** | Param | Type | Notes | |---|---|---| | `execution_id` | string, required | The id from the ⏸ block. | | `message` | string | The user's words: an answer, a "no", a modification. | | `approve` | boolean | `true` only after the user explicitly confirmed. | One of `message` / `approve: true` is required. **Example (approval):** `{"user_request": "yes, book it", "execution_id": "d3ad...", "approve": true}` **Example (answer):** `{"user_request": "the London office, not Paris", "execution_id": "d3ad...", "message": "The London office, not Paris"}` **Returns:** the agent's next turn (an approved action executes during this call — it can legitimately take ~30s), then either a fresh ⏸ block or `✅ Conversation resolved`. Both turns are saved to the run's thread. **Failures & fixes** - "Provide `message` or `approve: true`" → you sent neither. - "Execution not found" → wrong/foreign id; take it from the ⏸ block itself. - "No conversation session for this execution (expired or not a conversational agent)" → the pause window lapsed or the run never paused; use `plungeai_followup` for a finished run. - "This run isn't paused — it already completed. Use plungeai_followup..." → exactly that; `continue` is only for pending sessions. (A late `approve: true` on an already-consumed approval is safe — it answers that nothing is awaiting approval rather than re-running the action.) - "Agent continuation failed" → the engine failed OR the reply just didn't land within the ~30s poll while the action may still have executed. Retrying `approve: true` once is safe (the approval token is idempotent — the action never runs twice). For a `message`, check `plungeai_get_result` first — if the turn landed, a retry would send the message again as a second turn. Then surface to the user. --- ## plungeai_followup **Purpose:** ask a follow-up about a COMPLETED execution. Session-first: if the run's agent left a session, the SAME agent continues with its own context. Otherwise a research fallback answers using the run's stored result as prior context (and is instructed to web-verify any new factual claim — never to invent). **Parameters:** `execution_id` (required), `prompt` (required — the user's follow-up, ≤65536). **Example:** `{"user_request": "what about their European competitors?", "execution_id": "d3ad...", "prompt": "What about their European competitors?"}` **Returns:** the answer (relay verbatim), possibly ending in a ⏸ block if the continued agent paused again. The turn is appended to the run's conversation thread — a later `plungeai_get_result` on the same id shows the whole dialogue. **Failures & fixes:** "Execution not found" → wrong/foreign id. "Failed to retrieve follow-up response" → transient; retry once. If the stored result has expired the fallback researches from scratch — the answer may lack the original run's specifics; say so if it matters. --- ## plungeai_chat **Purpose:** persistent chat with the PlungeAI assistant — a conversational agent with web search and registry lookup. Conversations persist and appear identically in Studio's Think tab and the CLI. **Actions** | Action | Requires | Notes | |---|---|---| | `send` | `message` | Streams a reply. Omit `conversation_id` to auto-create a conversation (titled from the first message); pass it to continue one. The reply ends with `(conversation: <id>)` — reuse that id for every subsequent turn. | | `new` | — | Explicitly create a conversation first (optional `message` seeds the title); returns the id. | | `list_sessions` | — | Table of the user's conversations (Title, ID, Messages). | | `history` | `conversation_id` | The full transcript, rendered. | **Example:** `{"user_request": "what can this platform do?", "action": "send", "message": "What can this platform do?"}` **Returns:** the assistant's markdown + the conversation-id footer. Relay both — the footer is how the user (and you) come back to the thread. **Failures & fixes:** "message is required for send." / "conversation_id is required for history." → supply it. "Conversation not found" → wrong or foreign id; `list_sessions` to find the real one. Avoid firing two `send` calls into the same conversation concurrently — turns are persisted one-writer-at-a-time and a racing turn can be lost. --- ## Choosing among the three (quick rules) - ⏸ block on screen → `plungeai_continue`. Nothing else resumes a pause. - "Ask more about that run/report" → `plungeai_followup` with that run's id. - Free-standing conversation, no run in sight → `plungeai_chat`. - `continue` on a finished run redirects you to `followup`; `followup` on a paused run continues the pending session (it is session-first) — but the approval decision itself must still travel via `continue`. # MCP plane — /v1/mcp Source: https://docs-preview.plungeai.com/skills/plungeai-results-traces/references/mcp-runs <!-- sources-of-truth: orchestration/api-gateway/openapi.ts, orchestration/api-gateway/routes/mcp.ts, orchestration/mcp-executor/mcp-executor.ts, docs/ONE-API-DEVELOPER-GUIDE-2.0.md | last-synced: 2026-09-24 --> Two directions in one plane: - **Inbound** — the platform *is* an MCP server: point any MCP client at it and get the whole platform (execute agents, workflows, discovery, …) as MCP tools. - **Outbound** — the platform is an MCP *client* on your behalf: open a "run" against third-party MCP servers from the catalog and call their tools through one metered, tenant-isolated door. Auth: `Authorization: Bearer ozk_YOUR_KEY` on every route here. ## Inbound — use the platform from any MCP client Canonical Streamable-HTTP endpoints (both accept an `ozk_` bearer): - `https://mcp.plungeai.com/v1` — the dedicated MCP host - `https://api.plungeai.com/v1/mcp` — the same surface through the One API router Claude Code: ```bash claude mcp add plungeai --transport http https://mcp.plungeai.com/v1 \ --header "Authorization: Bearer ozk_YOUR_KEY" ``` Generic `mcpServers` JSON (Cursor, clients with config files): ```json { "mcpServers": { "plungeai": { "type": "http", "url": "https://mcp.plungeai.com/v1", "headers": { "Authorization": "Bearer ozk_YOUR_KEY" } } } } ``` Per-client install steps (Claude Desktop, Cursor variants, VS Code, …) are the per-editor `plungeai-in-*` skills' job (e.g. `plungeai-in-cursor`); this file covers the HTTP surface. Raw JSON-RPC 2.0 works too — `POST /v1/mcp` with the message as the body; responses come back as JSON, or SSE for streamed tool calls. The `Mcp-Session-Id` header is forwarded both ways — session-based flows must replay the one the server returns. ### GET /v1/mcp/tools — what the platform exposes as MCP tools Returns the standard JSON-RPC `tools/list` result (tool names like `plungeai_execute_workflow`, `plungeai_execute_agent`, …). List it live — the tool set evolves; never hardcode names or counts. ```bash curl -s https://api.plungeai.com/v1/mcp/tools \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "jsonrpc": "2.0", "id": 1, "result": { "tools": [ { "name": "plungeai_execute_agent", "description": "Execute a platform agent with a prompt", "inputSchema": { "type": "object", "properties": { "...": "..." } } }, { "name": "plungeai_execute_workflow", "description": "...", "inputSchema": { "...": "..." } } ] } } ``` ## Outbound — MCP runs Lifecycle: **open a run → list/call its tools → close it**. Runs are tenant-isolated (scoped to your key's identity) and **expire after 30 idle minutes**; close them explicitly when done anyway. Find `server_ids` in the catalog first: `GET /v1/discovery/search?kind=mcp-servers&q=<what you need>` (`plungeai-discovery`) — ids come from there, never from memory. ### POST /v1/mcp/runs — open a run Body: `{"server_ids": ["<registry mcp-server card id>", ...]}`. ```bash curl -s -X POST https://api.plungeai.com/v1/mcp/runs \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"server_ids": ["cloudflare-docs"]}' ``` HTTP **201**: ```json { "run_id": "00000000-0000-4000-8000-000000000007", "tools": [ { "name": "mcp__cloudflare-docs__search_cloudflare_documentation", "description": "Search Cloudflare documentation", "input_schema": { "type": "object", "properties": { "query": { "type": "string" } } } } ], "connected": ["cloudflare-docs"], "failed": [], "warnings": [], "skipped": [] } ``` Tool names are namespaced `mcp__<server>__<tool>`. Partial success is real: check `connected` vs `failed` vs `skipped` — a run can open with some servers up and others down (per-server errors are in `failed`). Errors: `400 invalid_body` (missing/empty `server_ids`), `502 no_servers_connected` — **none** of the requested servers came up; the body carries per-server failures plus the same `skipped` array. A server that just failed sits in a **60s cooldown**: re-opening immediately lists it in `skipped` (not re-attempted) while other servers connect normally. Wait out the cooldown before retrying it. ### GET /v1/mcp/runs/{id}/tools — the run's tool table ```bash curl -s https://api.plungeai.com/v1/mcp/runs/00000000-0000-4000-8000-000000000005/tools \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "tools": [ { "name": "mcp__cloudflare-docs__search_cloudflare_documentation", "description": "...", "input_schema": { "...": "..." } } ], "count": 1 } ``` An unknown or expired run id is **not a 404** here — it returns an empty tool table. Empty tools on a run you opened a while ago means the 30-idle-minute expiry hit: reopen the run. ### POST /v1/mcp/runs/{id}/call — call one tool Body: `{"name": "<namespaced tool>", "args"?: object, "timeout_ms"?: integer}`. ```bash curl -s -X POST https://api.plungeai.com/v1/mcp/runs/00000000-0000-4000-8000-000000000005/call \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "mcp__cloudflare-docs__search_cloudflare_documentation", "args": {"query": "durable objects alarms"}}' ``` ```json { "content": "# Search results\n\n1. Durable Objects Alarms — ..." } ``` Errors: `400 invalid_body` (no `name`), `502 tool_call_failed` — the message is always the fixed string `"MCP tool call failed"`; the upstream detail lives in the error envelope's **`content`** extra. One retry with backoff is reasonable, with one exception: a `content` of "no MCP servers are connected for this run (inject was not called, or state expired)" means the run id is unknown or idle-expired — **reopen the run**, don't debug the tool name. ### DELETE /v1/mcp/runs/{id} — close a run Idempotent — deleting an already-gone run still returns success. ```bash curl -s -X DELETE https://api.plungeai.com/v1/mcp/runs/00000000-0000-4000-8000-000000000005 \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "success": true } ``` ## Full outbound pattern (TypeScript, plain fetch) ```ts const BASE = 'https://api.plungeai.com' const H = { Authorization: `Bearer ${process.env.PLUNGEAI_API_KEY}`, // ozk_YOUR_KEY 'Content-Type': 'application/json' } // 1. open const run = await (await fetch(`${BASE}/v1/mcp/runs`, { method: 'POST', headers: H, body: JSON.stringify({ server_ids: ['cloudflare-docs'] }), })).json() if (!run.connected?.length) throw new Error(JSON.stringify(run.failed)) // 2. call (tool name taken from run.tools — never hardcoded) const tool = run.tools[0].name const res = await (await fetch(`${BASE}/v1/mcp/runs/${run.run_id}/call`, { method: 'POST', headers: H, body: JSON.stringify({ name: tool, args: { query: 'workers kv limits' } }), })).json() console.log(res.content) // 3. close await fetch(`${BASE}/v1/mcp/runs/${run.run_id}`, { method: 'DELETE', headers: H }) ``` # Observability — watching, debugging, and pricing platform runs Source: https://docs-preview.plungeai.com/skills/plungeai-results-traces/references/observability <!-- sources-of-truth: orchestration/api-gateway/openapi.ts (traces, request log), orchestration/cnl-engine/README.md (SSE events, execution summary), orchestration/cnl-engine/executors.ts, orchestration/mcp-gateway/server.ts, orchestration/scheduler/README.md | last-synced: 2026-09-24 --> Every execution on PlungeAI is observable at four altitudes: live events while it runs, an execution record after it finishes, a persisted span-level trace, and the gateway's own request log with cost. Debugging is reading these in order — not re-running the workload to "see what happens". ## Correlation ids — wire them in from the start - Every One API response echoes a server-generated **`x-request-id`**. - Pass your own **`x-trace-id`** header on One API calls to correlate a whole operation across planes (an agent execute + a result redeem + a model call under one trace). **Fallback rule:** if you never sent `x-trace-id`, the trace id IS that request's `x-request-id` — so a call you did not pre-correlate is still traceable: take the echoed `x-request-id` and use it in `GET /v1/traces/{id}`. - Every execution acknowledgement carries `workflow_id` (the execution id) and `request_id`. Log them; they are the keys to everything below. ## Live: SSE event stream Streaming execution (`POST /v1/workflows/{id}/execute-stream`, and MCP streamed runs) emits server-timestamped events in order: ``` request_received → workflow_loaded → workflow_started → task_dispatched (per task) → task_completed (per task) → workflow_completed → workflow_result ``` Per-task duration = that task's `task_completed` − `task_dispatched`, using the SERVER timestamps — client network jitter is excluded. This event stream is the ground truth for performance questions ("which branch was slow"); never time a run from your own clock around the request. ## After the run: status and history ### `plungeai_get_workflow_status {execution_id}` Structured status: `status`, `workflow_name`, `started_at`, `duration_ms`, `final_task_id`, `error_message` (non-null on failure), and — crucially — `continuation`: non-null when the run is PAUSED awaiting the user (an `ask_user` question or an approval gate), carrying the agent, the question, and any pending action summary (with price when it is a money action). Relay that to the user and resume with `plungeai_continue`. The status check also **self-heals stuck runs** — poll it before declaring a run dead. Full parameter/return contract: `plungeai-workflows` (`references/mcp.md`). ### `plungeai_executions` — the run ledger `action: list|get|output|conversation|delete`. `list` is the "what ran lately" view; `get` the record; `output`/`conversation` the content (final, user-ready markdown — relay verbatim). This is also your idempotency check: before re-firing anything with side effects, look here for what already ran. Full parameter/return contract: `plungeai-workflows` (`references/mcp.md`). ### Execution summary (per run) Every engine run reports: `total_tasks_executed`, `tasks_skipped`, `conditions_evaluated`, `nesting_levels_processed`, `parallel_blocks_executed`, `sequential_blocks_executed`, per-task durations (with attempts), and **`failed_branches[]`** — parallel branches that failed WITHOUT aborting the run. The key is present only when something was lost; its absence is the all-clear. Always check it before trusting a synthesis built over a fan-out. ## Deep: persisted traces ```bash curl -s https://api.plungeai.com/v1/traces/{traceId} \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` Returns two arrays: - **`spans`** — engine execution spans: `type` (`request_received`, `task_dispatched`, `task_completed`, `workflow_result`, …), `workflow_id`, `task_id`, `agent`, `status`, `duration_ms`, timestamp. Large payloads are stored by reference (`payload_ref`); small ones inline (`payload_inline`, guard-scanned, ≤1 KB) — traces never leak megabytes into your context. - **`gateway_requests`** — the router's own log per request: `plane`, `route`, `status`, `duration_ms`, and **`cost_usd`** where priced. This is where "what did that run cost" is answered; model usage is captured per task and priced post-hoc from the platform's pricing catalog. Full route detail (parameters, error shapes, the outbound-MCP variant of tracing): [`references/traces.md`](/skills/plungeai-results-traces/references/traces). ## Scheduler observability Scheduled work has its own ledger on top (see `plungeai-scheduling`): `plungeai_schedule {action: "stats"}` for the fleet (active/paused jobs, today's success/failure split, average duration) and `{action: "runs", job_id}` for one job's history — whose Execution ID column bridges into everything above. ## Quality signals in discovery Registry search accepts `include=quality`: each card gains `{score, success_rate, runs}` (null when unmeasured). Use it when choosing between similar agents — measured success beats description prose. ## The debugging playbook 1. **Run seems hung** → `plungeai_get_workflow_status` (self-heals; may return a `continuation` — the run is waiting on a human, not hung). 2. **Run failed** → status `error_message` → the trace's failing span (`status`, `agent`, `duration_ms`) → that agent's outcome remediation. 3. **Run "succeeded" but output is thin** → execution summary `failed_branches[]` and `tasks_skipped` (a false condition silently skips tasks — that is a feature, verify the condition). 4. **Slow** → per-task durations from events/spans. Parallel block cost = slowest child; a staircase of child durations against one destination means queueing at that service — spread destinations, don't widen the block (`plungeai-workflows`). 5. **Expensive** → `gateway_requests.cost_usd` by route + the run's per-task model usage; then cap with `effort`/`max_turns` (missions, `plungeai-missions`) or a cheaper `model` (`plungeai-models`). 6. **Behaved as if instructions were missing** → the run's warnings: capability ids that failed to resolve or were deferred over budget (`plungeai-skills-plugins`). ## What to log in YOUR integration Minimum for a production integration calling the platform: the `x-request-id` of every call, the `workflow_id`/`execution_id` of every run you start, and your own `x-trace-id` per user-visible operation. With those three, every incident is reconstructable from the platform side; without them you are grepping timestamps. # Traces — GET /v1/traces/{id} Source: https://docs-preview.plungeai.com/skills/plungeai-results-traces/references/traces <!-- sources-of-truth: orchestration/api-gateway/openapi.ts, docs/ONE-API-DEVELOPER-GUIDE-2.0.md | last-synced: 2026-09-24 --> The observability plane: one id follows a request across every internal hop. (This is the traces half of the One API's discovery+traces route group — for `/v1/discovery/*` see `plungeai-discovery`.) Auth: `Authorization: Bearer ozk_YOUR_KEY` on every route here. ## GET /v1/traces/{id} — the execution trace Every response from the API carries a server-minted `x-request-id`; that id is also a trace id. To correlate **multiple** calls (or to pick the id yourself), send an `x-trace-id` header and **keep your own copy** — it is threaded through every internal hop of every plane, but it is **not echoed on the response** (only `x-request-id` is). ```bash # 1. Execute with your own trace id curl -s -X POST https://api.plungeai.com/v1/agents/llm-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -H "x-trace-id: my-batch-2026-08-27-001" \ -d '{"prompt": "Say: traced"}' # 2. Read the whole story curl -s https://api.plungeai.com/v1/traces/my-batch-2026-08-27-001 \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "trace_id": "my-batch-2026-08-27-001", "spans": [ { "id": 101, "trace_id": "my-batch-2026-08-27-001", "workflow_id": "2cecae7f-...", "task_id": null, "ts": 1787706891000, "type": "request_received", "agent": null, "status": null, "duration_ms": null, "payload_ref": null, "payload_inline": "..." }, { "id": 102, "trace_id": "my-batch-2026-08-27-001", "workflow_id": "2cecae7f-...", "task_id": "t1", "ts": 1787706891200, "type": "task_dispatched", "agent": "llm-agent", "status": null, "duration_ms": null, "payload_ref": null, "payload_inline": null }, { "id": 103, "trace_id": "my-batch-2026-08-27-001", "workflow_id": "2cecae7f-...", "task_id": "t1", "ts": 1787706892100, "type": "task_completed", "agent": "llm-agent", "status": "success", "duration_ms": 900, "payload_ref": null, "payload_inline": "traced" }, { "id": 104, "trace_id": "my-batch-2026-08-27-001", "workflow_id": "2cecae7f-...", "task_id": null, "ts": 1787706892150, "type": "workflow_result", "agent": null, "status": "success", "duration_ms": 950, "payload_ref": null, "payload_inline": "traced" } ], "gateway_requests": [ { "id": "9f2c1e44-...", "trace_id": "my-batch-2026-08-27-001", "plane": "agents", "route": "/v1/agents/:id/execute", "user_id": "u-...", "status": 200, "upstream": "cnl-engine", "duration_ms": 1180, "cost_usd": null, "created_at": 1787706892 } ] } ``` Reading it: - **Span sequence**: `request_received → workflow_loaded → workflow_started → task_dispatched → task_completed → workflow_result`. A task with `retry` configured shows duplicate `task_dispatched` spans on the same `task_id`. - **Payloads**: `payload_inline` is guard-scanned text ≤1KB (secrets/PII come back redacted); larger payloads live behind `payload_ref` (a storage key, not a URL you can fetch through this API). - **`gateway_requests`** is the router's own request log for the same trace id — plane, route, status, upstream, latency, and cost where measured. - An unknown or still-lagging trace id returns **200 with empty arrays, never 404** — don't poll for a 404, poll until `spans` is non-empty (with a cap). Spans are written asynchronously and a read immediately after a request may lag by a few seconds; the route returns at most the first **500 spans**. Use traces to debug: a `502 engine_error` on execute + the trace for that request id shows exactly which hop failed and how long each took. The higher-altitude reads (live SSE events, execution summary, the debugging playbook) live in [`references/observability.md`](/skills/plungeai-results-traces/references/observability). # plungeai-scheduling Source: https://docs-preview.plungeai.com/skills/plungeai-scheduling Cron-schedule PlungeAI workflows, agent queries, pre-built agent cards, and condition-watching heartbeats via plungeai_schedule, with full run history and retries. Use when the user wants something to run daily/hourly/on a cron, a recurring report, a standing watchdog, or asks about job status, retries, or why a scheduled run didn't fire. For the workflow or mission being scheduled use `plungeai-workflows` / `plungeai-missions`; for a list-to-completion campaign's own cadence use `plungeai-campaigns`. [Download zip](https://skills.plungeai.com/plungeai-scheduling.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-scheduling/SKILL.md) The scheduler runs platform work unattended on cron expressions: a saved workflow every morning, an agent query hourly, a pre-built agent card nightly, or a condition-watching heartbeat. Every job has first-class run history — nothing here is fire-and-forget. ## Prerequisites - A self-service `ozk_` API key from **Dashboard → One API → Keys** (https://dashboard.plungeai.com), or an MCP client connected to `https://mcp.plungeai.com/v1`. - The thing being scheduled must already exist and be discoverable: `plungeai_list_workflows` for a saved workflow, `plungeai_list_agents {search: "…"}` for an agent/check_agent id — never guess an id, it is fence-checked at create time. ## Creating a job — `plungeai_schedule` Action-routed, one tool: ``` plungeai_schedule {action: "create", name: "Daily market brief", job_type: "workflow", # agent | query | workflow | heartbeat target: "<workflow id>", schedule: "0 7 * * *"} # 07:00 UTC daily plungeai_schedule {action: "list"} plungeai_schedule {action: "run_now", job_id: "…"} # always do this right after create plungeai_schedule {action: "runs", job_id: "…"} # Execution ID column → plungeai_get_result plungeai_schedule {action: "stats"} ``` Four `create` shapes — workflow (`target` = a workflow id you own), agent (`target` = an agent id + `parameters: {prompt}`), query (`target` = `{agent, query}` JSON), and heartbeat (`check_agent` + `condition_prompt`, ticks and only acts when the condition is met — of the five `notify_channel` values, telegram/discord/slack/email all deliver through the normal per-channel adapters; whatsapp is a known gap, prefer `trigger_workflow` or another channel for it). `mission_ref` on create schedules a pre-built agent card directly, resolved live at fire time. Standard 5-field cron, UTC, 1-minute minimum granularity, ±5s accuracy. Use the rolling date tokens (`{yesterday}`, `{week_start}`, `{last_week_end}`, …) instead of baking concrete dates into scheduled YAML — full table in [`references/scheduling.md`](/skills/plungeai-scheduling/references/scheduling). ## Verify every job you create `run_now` fires immediately and reports the REAL outcome plus a resolvable execution id — always call it right after `create` to prove the job works end-to-end, rather than waiting for the first natural fire. ## Gotchas - **Workflow jobs run by reference** — edit the workflow in Studio and the next scheduled run uses the latest saved version automatically; there is no "update the schedule to change the logic". - **Delete is soft** — history stays readable, but a deleted job refuses run_now/update/pause/resume; there is no undelete. - Failed runs auto-retry (3 attempts, 5 minutes apart) and **re-fire the FULL job** — schedule only idempotent work, or make the workflow itself idempotent. - A scheduler *run id* (`exec_...`, underscore) is not resolvable by `plungeai_get_workflow_status` / `plungeai_get_result` directly — go through `action: "runs"` and take its Execution ID column first. - Scheduled user workflows keep the full per-user memory lifecycle (recall + write) — only system jobs and heartbeat checks are memory-free. - `@once` fires once then soft-deletes; `runAgain` (a workflow's own last step) self-schedules the next `@once` run without any cron expression at all — the mechanism behind a campaign that "just keeps going." ## Related skills - `plungeai-workflows` — author the workflow a job runs. - `plungeai-missions` — author the mission a `mission_ref` job runs. - `plungeai-campaigns` — a list-to-completion ledger driven by cron or `runAgain`. - `plungeai-memory` — the recall/write lifecycle of a scheduled run. - `plungeai-results-traces` — read a job run's status, output, and trace once you have its Execution ID. ## Reference - [`references/scheduling.md`](/skills/plungeai-scheduling/references/scheduling) — full action table, cron/date-token reference, heartbeat semantics, retries/history, troubleshooting, and the `plungeai_schedule` MCP tool contract. ## Reference pages <CardGroup cols={2}> <Card title="Scheduling — cron jobs for workflows, agents, and missions" icon="file-text" href="/skills/plungeai-scheduling/references/scheduling"> The scheduler runs platform work unattended on cron expressions: a saved workflow every morning, an agent query hourly, a pre-built agent card nightly. </Card> </CardGroup> # Scheduling — cron jobs for workflows, agents, and missions Source: https://docs-preview.plungeai.com/skills/plungeai-scheduling/references/scheduling <!-- sources-of-truth: orchestration/scheduler/README.md, orchestration/scheduler/CLAUDE.md, orchestration/scheduler/SchedulerDO.ts (heartbeat delivery), orchestration/scheduler/delivery.ts, orchestration/mcp-gateway/server.ts, orchestration/mcp-gateway/tools.ts, orchestration/mcp-gateway/extras.ts, orchestration/cnl-engine/README.md (date tokens) | last-synced: 2026-09-24 --> The scheduler runs platform work unattended on cron expressions: a saved workflow every morning, an agent query hourly, a pre-built agent card nightly. Jobs, run history, retries, and stats are first-class — a scheduled job is not fire-and-forget; every run is logged and resolvable like any other execution. ## Creating and managing jobs — `plungeai_schedule` One MCP tool, action-routed: ``` plungeai_schedule {action: "create", name: "Daily market brief", job_type: "workflow", # agent | query | workflow | heartbeat target: "<workflow id>", schedule: "0 7 * * *" # 07:00 UTC daily } plungeai_schedule {action: "list"} plungeai_schedule {action: "get", job_id: "…"} plungeai_schedule {action: "update", job_id: "…", schedule: "0 8 * * 1-5"} plungeai_schedule {action: "pause", job_id: "…"} plungeai_schedule {action: "resume", job_id: "…"} plungeai_schedule {action: "run_now", job_id: "…"} # returns the run's REAL outcome + execution id plungeai_schedule {action: "runs", job_id: "…"} # execution history plungeai_schedule {action: "stats"} plungeai_schedule {action: "delete", job_id: "…"} ``` Also on create: `mission_ref` schedules a pre-built agent card directly (a bounded mission on cron — see `plungeai-missions`), and `parameters` carries the run input. ### Heartbeat jobs — watch a condition, act only when it trips `job_type: "heartbeat"` is a user-facing job kind (not just internal plumbing): each tick it runs `check_agent` against `condition_prompt` and only acts when the condition is met. Create requires `name`, `schedule`, `check_agent`, `condition_prompt`; optional actions: `trigger_workflow` (a workflow id to fire) and `notify_channel` (`telegram | whatsapp | discord | slack | email`) + `notify_chat_id`. Heartbeat notify routes through the same per-channel delivery adapters as ordinary scheduled-result delivery — telegram/discord/slack/email all deliver (subject to each channel's normal pairing/confirmation fence, see `plungeai-campaigns`' delivery-channel table); **whatsapp has a known gap** — the heartbeat payload never carries the `phone_number_id` the whatsapp adapter requires, so a whatsapp target silently no-ops today. ``` plungeai_schedule {action: "create", job_type: "heartbeat", name: "Price watch", schedule: "*/30 * * * *", check_agent: "<agent id from a live search>", condition_prompt: "Is BTC below $50k? Answer MET or NOT MET with evidence.", notify_channel: "telegram", notify_chat_id: "…"} ``` Heartbeat condition checks run memory-free — they are watch-and-notify ticks, not learning runs. Semantics you should rely on: - **Workflow jobs run by reference** — the scheduler stores a pointer, not a YAML copy. Edit the workflow in Studio and the next scheduled run uses the latest version automatically. Never "update the schedule" to change workflow logic. - **Agent and query jobs are auto-wrapped at create time** into a saved one-task workflow (`Scheduled: <name>`) and scheduled as workflow jobs — so their runs get full standard execution history too. - **Delete is soft**: history stays readable; a deleted job refuses run_now/update/pause/resume. There is no undelete — create a new job. - **`run_now` returns the real outcome** plus a resolvable execution id — use it to verify a job end-to-end right after creating it (always do this). ## Cron expressions Standard 5-field cron, minimum granularity **1 minute**, evaluated in UTC: ``` minute hour day month day-of-week ``` | Intent | Expression | |---|---| | Every 5 minutes | `*/5 * * * *` | | Hourly on the hour | `0 * * * *` | | Daily 07:00 | `0 7 * * *` | | Weekdays 09:00 | `0 9 * * 1-5` | | Mondays 09:00 | `0 9 * * 1` | | 1st of month 00:00 | `0 0 1 * *` | `,` lists, `-` ranges, `/` steps, `*` any. Cron accuracy is ±5 seconds — do not build designs that need tighter timing. ### `@once` and `runAgain` — one-time and self-scheduling jobs `@once` is a valid schedule that fires exactly once, at the job's explicit next-run time, then soft-deletes itself (run history survives). A failed `@once` run may retry once with the standard +5 min delay before its final deletion. `runAgain` is the mechanic behind a **campaign** that re-schedules itself without a cron expression: the last row of its per-cycle pipeline is `agent: scheduler, params: {operation: "runAgain", in: "1h"}`. It creates exactly ONE `@once` job for that workflow (never stacks — an existing pending `@once` job for the same workflow is re-timed, not duplicated). `in` accepts a duration (`5m`, `1h`, `90s`) or a number of seconds, default `1h`. This is orthogonal to a campaign scheduled *with* a cron expression, which is driven by an ordinary recurring job instead — see `plungeai-campaigns`. ## Date tokens — schedules that reason about time windows Scheduled workflows should never bake concrete dates into YAML. The engine seeds rolling tokens from each run's execution time — same `{placeholder}` syntax as inputs, lower precedence than caller inputs: `{now}` `{today}` `{yesterday}` `{week_start}` `{week_end}` `{last_week_start}` `{last_week_end}` `{month_start}` `{month_end}` `{last_month_start}` `{last_month_end}` — all UTC, ISO weeks (Monday = day 1). ```yaml - type: task id: compare agent: llm-agent prompt: | Compare this week ({week_start} to {week_end}) against last week ({last_week_start} to {last_week_end}). Identify the notable moves. ``` The scheduler passes the execution time automatically — a job scheduled "Monday 09:00" reasons about the correct ISO week every time, forever, with zero YAML edits. ## Runs, retries, and history - Every run is logged: status (`running` → `completed`/`failed`), start/end, duration, result pointer, error message, attempt number, what triggered it (schedule vs manual). - **Failed runs auto-retry**: up to 3 attempts by default, 5 minutes apart; after max retries the job returns to its normal schedule (it is not paused by failure). The per-job `max_retries` override is settable only on the REST/Studio surface (`POST /jobs`) — `plungeai_schedule` has no such field. - Retry re-fires the full job — schedule only idempotent work, or make the workflow itself idempotent (e.g. keyed upserts), for anything with side effects. - `action: "runs"` lists history; its **Execution ID column** is the id to fetch output with `plungeai_get_result` / inspect with `plungeai_get_workflow_status`. A scheduler *run id* itself is NOT resolvable by those tools — both will tell you to go through `runs` first; do that instead of retrying. - `action: "stats"` summarizes: total/active/paused jobs, today's runs and success/failure split, average duration — the first read when "schedules seem broken". ## Memory semantics of scheduled runs A scheduled user workflow keeps the FULL per-user memory lifecycle — it recalls and writes long-term memory exactly like a manual run (owner decision; see `plungeai-memory`). Only system jobs and heartbeat condition checks run memory-free. Design accordingly: a daily mission genuinely accumulates knowledge run over run. ## Patterns - **Morning brief:** workflow (parallel news/search fan-out → synthesis) on `0 7 * * *`, date tokens for "since yesterday". - **Weekly comparison report:** workflow with `{last_week_*}` vs `{week_*}` windows on `0 9 * * 1`. - **Standing watchdog:** `quick`-effort mission card via `mission_ref` hourly; it checks a condition and only escalates (writes/notifies) when triggered. - **Data hygiene:** batch workflow nightly over a table; opt in with `track: true` on the batch so re-runs resume instead of repeat (`plungeai-workflows`). - **Campaign cadence:** a list-to-completion campaign is driven either by an ordinary recurring cron job or by its own `runAgain` self-scheduling — see `plungeai-campaigns`. ## Troubleshooting 1. Job not firing → `get` the job: `status` must be `active` and next run in the future; then `runs` for the last attempt's error. 2. Run failed → `runs` → take the Execution ID → `plungeai_get_workflow_status` (which also self-heals stuck runs) and the trace (`plungeai-results-traces`). 3. Wrong data window → check UTC: `0 7 * * *` is 07:00 UTC, not local; date tokens are UTC/ISO too. 4. Output looks stale → the job runs the workflow by reference; confirm which version is saved (someone may have edited it — that IS the version that runs). --- ## MCP tool: `plungeai_schedule` **Purpose:** cron-scheduled jobs — run agents, workflows, or condition-check heartbeats on a schedule. Jobs are ownership-scoped. **Actions** | Action | Requires | Notes | |---|---|---| | `stats` | — | Job counts by status. | | `list` | — | Table: Name, Type, Schedule, Status, Next run, ID. | | `get` | `job_id` | Full job JSON. | | `create` | see below | Four job shapes (below). | | `update` | `job_id` (+ any of name/description/schedule/target/parameters) | Deleted jobs refuse it. | | `pause` / `resume` | `job_id` | Toggle `paused`/`active`. | | `delete` | `job_id` | SOFT delete — run history stays readable via `runs`; deleted jobs refuse run_now/update/pause/resume. | | `run_now` | `job_id` | Fire immediately; reports the run's REAL outcome and a resolvable execution id. | | `runs` | optional `job_id` | Run history table; its **Execution ID** column is what `plungeai_get_result` accepts. | **Create — the four shapes** 1. **Workflow job:** `job_type: "workflow"`, `target: "<workflow_id you own>"`, `name`, `schedule` (cron). The workflow must exist in the caller's account. 2. **Agent job:** `job_type: "agent"`, `target: "<agent-id>"`, `parameters: {"prompt": "what to do each run"}`, `name`, `schedule`. The agent is fence-checked NOW (unknown/inactive refused at create, not at fire time), and the job is auto-wrapped into a visible saved workflow ("Scheduled: <name>") so runs land in normal execution history. 3. **Query job:** `job_type: "query"`, `target` is JSON: `{"agent": "<agent-id>", "query": "<what to run>"}` — same wrapping and fence as agent jobs. 4. **Heartbeat:** `job_type: "heartbeat"`, plus `check_agent`, `condition_prompt` (required), optional `trigger_workflow` (workflow id to fire when the condition is met), `notify_channel` (`telegram|whatsapp|discord|slack|email`) + `notify_chat_id`. Each tick it checks the condition and only acts when met. Delivery runs through the same per-channel adapters as regular scheduled-result delivery — telegram, discord, slack, and email all deliver; ⚠️ **whatsapp is a known gap** (the heartbeat payload doesn't carry the `phone_number_id` the adapter requires, so it silently no-ops) — prefer `trigger_workflow` or another channel for a whatsapp-bound notice. Also on create: `mission_ref: "<agent-card-id>"` (+ `name`, `schedule`, optional `parameters.prompt`) schedules a pre-built agent card — the card resolves LIVE at fire time, so card edits apply to future runs automatically. **Example** ```json {"user_request": "every weekday at 7am send me an AI news brief", "action": "create", "name": "Morning AI brief", "job_type": "agent", "target": "brave-agent", "schedule": "0 7 * * 1-5", "parameters": {"prompt": "Top AI news of the last 24h, with links"}} ``` **Failures & fixes** - "create requires: name, job_type (agent|query|workflow), target, schedule" → supply them (heartbeat/mission_ref list their own requireds). - Fence refusal on `target`/`check_agent` → re-discover with `plungeai_list_agents`; never retry the same id. - "Agent schedules need a prompt" → add `parameters: {"prompt": ...}`. - "No workflow `<id>` found in your account" → pass an id from `plungeai_list_workflows` or build one first. - "That looks like an execution id (`exec_...`), not a job id (`job_...`)" → execution ids identify single runs; use `action: "runs"` to list them, or pass the job id. - "The scheduler's storage is briefly busy... Retry in a few seconds." → transient; the job most likely still exists — do NOT treat as not-found. - `Scheduler error (HTTP <status>).` (e.g. `Scheduler error (HTTP 401).`) → the gateway→scheduler hop itself failed; not your arguments. Report it rather than retry-looping. - To fetch a scheduled run's output: `action: "runs"` → take the **Execution ID** column → `plungeai_get_result {workflow_id: <that id>}`. # plungeai-skills-plugins Source: https://docs-preview.plungeai.com/skills/plungeai-skills-plugins Declare and understand PlungeAI's capability-injection fields on a type: harness task or plungeai_run_mission — skills, experts, persona, backgrounds, plugins, and MCP servers — including eager-vs-deferred budgets and degrade-to-warning failure semantics. Use when the user wants an agent to follow a house style or method, adopt an identity/voice, get standing company context, or wire in a domain toolkit or MCP server. For authoring the mission itself use `plungeai-missions`; for saving a skill from this chat use `plungeai-memory`'s plungeai_learn. [Download zip](https://skills.plungeai.com/plungeai-skills-plugins.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-skills-plugins/SKILL.md) Six capability kinds shape a `type: harness` task (or `plungeai_run_mission`) beyond its goal: **skills** (methods — HOW), **experts** and **personas** (identity — WHO), **backgrounds** (ambient truth), **plugins** (bundled domain toolkits), and **mcp** (connected servers). All six are resolved by one enrichment pass at run start. ## Prerequisites - A self-service `ozk_` API key from **Dashboard → One API → Keys** (https://dashboard.plungeai.com), or an MCP client connected to `https://mcp.plungeai.com/v1`. - **Discover every id before declaring it** — a missing id never fails the run, it degrades to a silent warning: `plungeai_list_agents {kind: "skills"|"experts"| "personas"|"connectors", search: "<topic>"}` (REST: `GET /v1/discovery/search?kind=…&q=…`). Never guess. ## Declaring capabilities ```yaml - type: harness goal: "Build a valuation snapshot for {input}" mission: | You are a buy-side analyst. persona: analyst experts: [securities-law] skills: [dcf-modeling-method] backgrounds: [acme-corp] plugins: [finance-bundle] mcp: [daloopa] ``` Injection order into the system prompt is fixed: `BACKGROUND` (verbatim, first) → persona text → `EXPERT` sections → skill bodies under `ADDITIONAL INSTRUCTIONS` → free-text `instructions:` (always appended, last word). ## The eager budget — the thing that trips people up All eager identity/instruction text shares **one 24 KB budget**: at most 3 backgrounds, 1 persona, 3 experts, 5 skills load eagerly; the rest **defer** to an `## AVAILABLE ON DEMAND` index the agent can pull mid-run with `load_skill`. Order your lists by importance — must-follow items go first or into `instructions:` (which always lands, never defers). A plugin's bundled skills are always indexed, never eagerly injected, regardless of count — see [`references/plugins.md`](/skills/plungeai-skills-plugins/references/plugins). ## Which to declare | You have | Declare | |---|---| | One instruction pack (method, house style) | `skills: [id]` | | An identity/voice for the whole run | `persona: id` (exactly one) | | A domain judgment lens | `experts: [id]` (up to 3 eager) | | Standing company/product context for every run in a family | `backgrounds: [id]` | | A coherent toolkit (several skills + scripts, versioned together) | `plugins: [id]` | | One MCP server the agent should call directly | `mcp: [server-id]` — plugins never add this for you | Do not unbundle a plugin into individual `skills:` entries to force eager injection — you lose its script index and blow the shared budget. A plugin's `.mcp.json` / manifest `mcpServers` documents the connectors its skills were written for; it is NOT auto-connected — declare that server's id yourself in `mcp:` alongside the plugin ([`references/plugins.md`](/skills/plungeai-skills-plugins/references/plugins)). ## Gotchas - Arrays REPLACE, never union, across mission-card merge (last wins: card → workflow root → task) — a task-level `experts: [x]` replaces the card's whole list. - Only the FIRST entry of `personas: [x]` (plural) is used — you never get a blend. - Missing/bad ids degrade to a warning, never a hard failure — a run that "lost its voice" or ignored a skill almost always has one in its warnings (`plungeai-results-traces`). - A plugin declaration never fails the run even if it can't be expanded — a bad id degrades to a warning and the plugin's skills/scripts are simply absent. ## Related skills - `plungeai-missions` — the harness task these fields attach to, and the merge order (card → workflow root → task). - `plungeai-memory` — `plungeai_learn` distills a chat session into a new skill. - `plungeai-results-traces` — where a degraded-capability warning shows up. - `plungeai-tools-connectors` — MCP server ids for the `mcp:` field. ## Reference - [`references/skills.md`](/skills/plungeai-skills-plugins/references/skills) — declaring/creating skills, the eager budget, debugging. - [`references/plugins.md`](/skills/plungeai-skills-plugins/references/plugins) — plugin expansion (skill index, MCP servers, script index), failure semantics. - [`references/experts-personas.md`](/skills/plungeai-skills-plugins/references/experts-personas) — backgrounds, persona, experts: injection order, budgets, merge behavior. ## Reference pages <CardGroup cols={2}> <Card title="Experts, personas, backgrounds — shaping WHO the agent is in a run" icon="file-text" href="/skills/plungeai-skills-plugins/references/experts-personas"> Three capability kinds shape an agent's identity and framing (as opposed to skills, which shape its methods). </Card> <Card title="Plugins — bundles of skills, MCP servers, and scripts injected as one unit" icon="file-text" href="/skills/plungeai-skills-plugins/references/plugins"> A plugin is a Claude-Code-format bundle stored on the platform: a directory tree containing any number of SKILL.md skills, an optional .mcp.json (or manifest… </Card> <Card title="Skills — injectable instruction packs for agent runs" icon="file-text" href="/skills/plungeai-skills-plugins/references/skills"> A skill is a markdown instruction pack (the Agent Skills SKILL.md format: frontmatter name + description, then the body) stored on the platform and injected… </Card> </CardGroup> # Experts, personas, backgrounds — shaping WHO the agent is in a run Source: https://docs-preview.plungeai.com/skills/plungeai-skills-plugins/references/experts-personas <!-- sources-of-truth: core/core-base/pack-enrich.ts, orchestration/cnl-engine/harness-mission.ts, orchestration/cnl-engine/schema-types.ts | last-synced: 2026-09-24 --> Three capability kinds shape an agent's identity and framing (as opposed to skills, which shape its methods). All three inject into the **front** of the system prompt, in a fixed order, before anything else the run adds: ``` ## BACKGROUND: <id> ← ambient truth, first, verbatim <background body> <persona text> ← identity and voice ## EXPERT: <id> ← labeled domain lenses <expert body> ``` The order is load-bearing: backgrounds frame everything that follows, and putting them first keeps the prompt prefix stable across runs sharing a background (prompt caching). Experts are labeled sections precisely so the model can tell "domain lens" apart from "who I am". ## Backgrounds — always-on ambient context A **background** is a registry card whose body is standing context: company facts, product truth, an environment description. Injected FIRST and **verbatim** — no stripping — because ambient truth must arrive intact. ```yaml - type: harness goal: "Draft the Q3 partner update" mission: | Write the quarterly partner update. backgrounds: [acme-corp] ``` Use a background when every run in a family needs the same grounding ("what Acme is, our products, our tone"), instead of pasting boilerplate into each mission text. Backgrounds are per-owner resolvable: your private background card wins for your runs. ## Persona — one voice per run A **persona** is an identity/voice text (from the platform's persona store). Exactly **one** per run — a run speaks with one voice. ```yaml persona: analyst ``` Accepted spellings, all normalized to the same thing: `persona:` (canonical), `digital_twin:` (alias), and `personas: [x]` (plural from preset frontmatter — only the FIRST entry is used). If you list several personas, you did not get a blend; you got `personas[0]`. Personas also appear outside missions: `plungeai_execute_agent`/`POST /v1/agents/{id}/execute` accept a `persona` parameter, and CNL `debate`/`validate` blocks take `persona`/`digital_twin` per debater, judge, and validator — the same store, applied per role. That is the idiomatic way to run a multi-perspective panel: one debate block, different personas per debater. ## Experts — labeled domain lenses (UI name: Specialists) An **expert** is deep domain instruction material injected as a labeled `## EXPERT: <id>` section — "reason like a securities lawyer", "apply SRE practices". Up to **3** load eagerly per run. ```yaml experts: [securities-law, python-pro] ``` Persona vs expert, the practical line: persona = who the agent IS (voice, identity — one). Expert = what the agent additionally KNOWS HOW to judge (lenses — up to three eager). A hedge-fund panel is personas in a debate; a compliance review is one persona plus a law expert. ## Budgets and degradation (shared with skills) All eager identity/instruction text — backgrounds + persona + experts + skills — shares **one 24 KB budget**, with per-kind caps: 3 backgrounds, 1 persona, 3 experts (5 skills). Over cap or over budget, items **defer**: the prompt lists them under `## AVAILABLE ON DEMAND` and the agent can pull one mid-run with `load_skill` (matching type). Persona is never deferred — it either resolves or warns. Missing ids never fail the run; they degrade to warnings: - `background "<id>" not found or empty` - `persona "<id>" not found` - `expert "<id>" not found` A run that "lost its voice" or ignored company context almost always has one of these warnings — check the run detail (`plungeai-results-traces`). The other classic cause: declaring more than the caps and assuming everything injected. Order lists by importance; the head injects, the tail defers. **Discover valid ids before declaring them** — the degrade-to-warning behavior means a guessed id fails silently: `plungeai_list_agents {kind: "experts", search: "…"}` or `{kind: "personas", search: "…"}` (REST: `GET /v1/discovery/search?kind=…&q=…`). ## Merge behavior in missions Like every mission field, these merge per key with **last-wins** across pre-built card → workflow root → task, and **arrays REPLACE rather than union** (see `plungeai-missions`). So a task-level `experts: [x]` replaces the card's expert list — and an explicit empty `experts: []` deliberately clears it. To ADD to a card's list you must restate the full list. ## Authoring guidance - Keep each body lean and self-contained: it lands in a prompt with everything else competing for 24 KB. A 15 KB background starves persona and experts. - Backgrounds: facts, not instructions. Instructions belong in mission text or skills — a background that says "always do X" fights the mission's own framing. - Experts: method and judgment criteria ("what a great X checks first"), not essays. - Test identity injection cheaply: run a `quick`-effort mission whose goal is to introduce itself and state its operating context; the answer shows exactly which layers landed. # Plugins — bundles of skills, MCP servers, and scripts injected as one unit Source: https://docs-preview.plungeai.com/skills/plungeai-skills-plugins/references/plugins <!-- sources-of-truth: core/core-base/pack-enrich.ts (expandPlugin), orchestration/cnl-engine/schema-types.ts | last-synced: 2026-09-24 --> A **plugin** is a Claude-Code-format bundle stored on the platform: a directory tree containing any number of `SKILL.md` skills, an optional `.mcp.json` (or manifest `mcpServers`) documenting the MCP servers its skills were written for, and executable Python scripts. Declaring ONE plugin on a mission indexes the whole bundle's skills and scripts in a single id — its documented MCP servers are NOT auto-connected (below). Real plugins are big (a serious finance bundle ships a dozen skills, several scripts, and references to multiple MCP servers), which drives the design below: plugins are **indexed, never dumped**. ## Declaring a plugin ```yaml - type: harness goal: "Build a valuation snapshot for {input}" mission: | You are a buy-side analyst. plugins: [finance-bundle] ``` Also accepted flat on the task alongside `skills`/`experts`/`mcp` (see `plungeai-missions` for the full authoring contract), and stored pre-built agent cards may declare plugins that merge into every run referencing the card. ## What expansion actually injects When the run starts, each declared plugin expands into two injected things (skills, scripts) plus one thing it deliberately does NOT do (auto-connect MCP servers): ### 1. A skill INDEX — progressive disclosure, deliberately Every bundled `SKILL.md` is indexed by **name + description only** (read from its frontmatter). The agent's prompt gets: ``` ## PLUGIN CAPABILITIES These skills come from the plugins in this mission. Only their names and descriptions are loaded. When one is relevant, read its full instructions FIRST with load_skill {type: "plugin_skill", plugin: "<plugin>", path: "<path>"} — then follow them. - **dcf-modeling** — Build a discounted-cash-flow model from … (plugin: finance-bundle · path: skills/dcf-modeling/SKILL.md) - … ``` Why an index and not the bodies: injecting bodies would burn the run's entire eager prompt budget (24 KB shared — see `skills.md`) on text the agent may never need, and an arbitrary-order "first five" cutoff would leave the rest unreachable. With the index, **every** bundled skill is discoverable and the agent pays for a body only when it decides it is relevant. There is no cap on index size. Consequence: a plugin skill influences the run ONLY if the agent loads it. If a particular bundled procedure MUST apply, say so in the mission text ("follow the dcf-modeling skill from the finance bundle") — the agent will then load it first. ### 2. MCP servers are NOT auto-connected — declare them yourself A plugin's `.mcp.json` / manifest `mcpServers` are the connectors its bundled skills were WRITTEN FOR, not an instruction to connect them: `expandPlugin` deliberately ignores them. An earlier version folded them into the run and silently connected 7–12 paid SaaS servers per plugin for runners who never authorized them (a wall of 401/`needs_connection` steps before the first turn) — so declaring a plugin injects only its skill index and script index (below); the run's live MCP set is the mission's own `mcp:` field alone. If a bundled skill needs a server, declare that server id yourself in `mcp:` alongside the plugin (see the skill's own text/card for which id to use — `plungeai-tools-connectors` for discovering connector ids). ### 3. A script index for `run_python` Every bundled `.py` file is indexed (never injected as text): ``` ## PLUGIN SCRIPTS Executable scripts from the plugins in this mission (run with run_python, referencing plugin + path): - finance-bundle: scripts/wacc.py ``` The agent executes them with its `run_python` tool, referencing plugin + path. This is how a plugin ships deterministic computation alongside instructions — prefer a bundled script over asking the model to do arithmetic. ## Failure semantics Plugin resolution never kills a run. Degradations surface as warnings: | Warning | Meaning | Fix | |---|---|---| | `plugin "<id>" not found in plugin-memory` | Bad id or unpublished bundle | Verify the id; publish the bundle | | `plugin "<id>" could not be expanded` | Retrieval failed mid-expand | Transient — re-run; check platform status | | `plugins declared but PLUGIN_MEMORY_SERVICE is not bound` | The executing surface has no plugin store | Run the mission on the standard engine surface | A run that "should have had the toolkit" but behaved bare almost always has one of these warnings in its detail — check `plungeai-results-traces` for where to read them. Because resolution degrades silently, look ids up before declaring them: MCP server ids for `mcp:` lists come from `plungeai_list_agents {kind: "connectors", search: "…"}` (see SKILL.md "Discovery first" for the other injectable kinds); plugin bundle ids live in plugin-memory — verify one cheaply by declaring it on a `quick` mission and checking the run's warnings. ## Plugins vs skills vs MCP — which to declare | You have | Declare | |---|---| | One instruction pack | `skills: [id]` — cheaper, eagerly injected | | An MCP server the agent should call | `mcp: [server-id]` directly — plugins never add this for you | | A coherent domain toolkit (several skills + scripts, maintained together; documented MCP servers to declare alongside it) | `plugins: [id]` — one id, whole skill/script kit, versioned as a unit | Do not unbundle a plugin into individual `skills:` entries to force eager injection — you lose the script index and blow the budget. State the must-follow skill in the mission text instead. If the bundle's skills call out an MCP server, add that server's id to `mcp:` yourself — declaring the plugin alone will not connect it. # Skills — injectable instruction packs for agent runs Source: https://docs-preview.plungeai.com/skills/plungeai-skills-plugins/references/skills <!-- sources-of-truth: core/core-base/pack-enrich.ts, orchestration/mcp-gateway/server.ts, orchestration/HARNESS-README.md, apps/ocean-skills/README.md | last-synced: 2026-09-24 --> A **skill** is a markdown instruction pack (the Agent Skills `SKILL.md` format: frontmatter `name` + `description`, then the body) stored on the platform and injected into agent runs. Where a workflow tells an agent WHAT to do, a skill tells it HOW: a method, a house style, a domain procedure, distilled research. Skills are per-user unless published; the same mechanism also powers platform-provided skills. Skills are one of six capability kinds a mission can declare (`skills`, `experts`, `persona`, `backgrounds`, `plugins`, `mcp`) — all resolved by the same enrichment pass. This file covers skills; siblings cover the rest (`experts-personas.md`, `plugins.md`). ## Declaring skills on a run Flat on any `type: harness` task (or in `plungeai_run_mission`): ```yaml - type: harness goal: "Audit {input} for compliance gaps" mission: | You are a meticulous compliance auditor. skills: [compliance-audit-method, house-style] ``` The engine resolves every declared id in ONE parallel pass and injects the bodies into the agent's prompt under `## ADDITIONAL INSTRUCTIONS` (frontmatter and heading noise stripped — only the instructions land). Mission-level free-text `instructions:` are appended after skill bodies, so author instructions always get the last word. ## The eager budget — why not everything is injected Injection is **budgeted**, deliberately: eager text across backgrounds + persona + experts + skills shares one cap (24 KB), and at most **5 skills** load eagerly (experts cap at 3, backgrounds at 3). Beyond the caps or the byte budget, skills are not dropped — they are **deferred**: the agent's prompt gets an `## AVAILABLE ON DEMAND` index listing them by id, and the agent pulls a body mid-run with its `load_skill` tool when it judges one relevant. Consequences for you: - **Order your `skills:` list by importance.** The first ids get eager injection; the tail defers. - Declaring 12 skills is legal but means 7+ are on-demand — fine for reference material, wrong for must-follow rules. Must-follow goes first or into `instructions:`. - A missing id does not fail the run: it degrades to a warning (`skill "<id>" not found`) and the mission runs without it. Check warnings when a run ignores instructions you thought you injected — the usual cause is a typo'd id silently degraded. - **Discover valid skill ids before declaring them**: `plungeai_list_agents {kind: "skills", search: "<topic>"}` (REST: `GET /v1/discovery/search?kind=skills&q=…`). Never guess an id — the degrade-to- warning behavior means a guessed id fails silently. ## Creating skills ### From a chat/agent session: `plungeai_learn` ``` plungeai_learn {source: "<a URL, pasted PDF text, or distilled findings from this chat>"} ``` Runs the platform's `learn` agent: reads the source, writes a lean SKILL.md body, and saves it **private to you**. Async by default — poll `plungeai_get_workflow_status`, fetch with `plungeai_get_result`. This is the "learn-back" move: when a session produced real research, offer to distill it so future runs can inject it. Full tool contract: `plungeai-memory`. ### From inside a mission Loop agents carry a `skill_manage` tool — a mission can save or update a skill as part of its work (e.g. a nightly job that maintains a "current market context" skill). ### Quality bar for a skill body The injector strips frontmatter and `#` headings, so write bodies that survive that: imperative instructions, concrete rules, short examples. A skill that is one big heading outline injects as almost nothing. Keep bodies lean — remember they share a 24 KB budget with everything else; a 20 KB skill starves the rest of the pack. ## Using skills without a mission `skill-agent` (registry) executes a prompt WITH a persona/skill applied — the one-shot way to get skill-shaped behavior without authoring a harness task. Discover it live (`plungeai_list_agents {search: "persona-based analysis"}`) and check its card for parameters. ## Platform skill packs (this one included) The `plungeai*` skill family you are reading is itself distributed through this system. What works today: the platform-internal variant is stored in skill-memory, so missions can declare `skills: [plungeai-workflows]` and get the CNL authoring rules injected — useful when a mission itself must write workflows. The public mirror (`npx skills add PlungeAI/plungeai-agent-skills` and the Claude Code plugin) is not published yet — until it ships, install from the platform or per your administrator. ## Debugging checklist 1. Run ignored a skill → check the run's warnings for `not found` / deferral notes (`plungeai-results-traces` shows run detail). 2. Skill listed under AVAILABLE ON DEMAND but never loaded → the agent judged it irrelevant; make the mission text reference it explicitly, or move it earlier in the list. 3. Behavior must be guaranteed → put it in `instructions:` (always appended) rather than relying on a skill body surviving the budget. 4. Verify what a saved skill contains before trusting injection: run a quick mission whose goal is to `load_skill` it and echo the body. # plungeai-tools-connectors Source: https://docs-preview.plungeai.com/skills/plungeai-tools-connectors Call PlungeAI structured tool-agents with typed parameters against a published invocation contract: fetch the contract (`plungeai_get_tool_contract` / `GET /v1/tools/{id}`), execute with typed `params` (`plungeai_execute_tool` / `POST /v1/tools/{id}/execute`), read live connected-account/credential status, and handle the trust fence (gated/money operations refuse unattended — `403 refused` on REST, `needs_approval`/`needs_connection` outcomes on MCP). Use when a card has a Parameters table (document conversion, weather, data-table CRUD, calendar, payments, posting), before the first call to an unfamiliar tool, or when fixing a `422 invalid_params` / `403 refused` / `needs_connection` response. For prompt-driven agents use `plungeai-agents`; for finding a tool id or contract use `plungeai-discovery`; for the model catalog use `plungeai-models`. [Download zip](https://skills.plungeai.com/plungeai-tools-connectors.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-tools-connectors/SKILL.md) A **tool** is a structured agent: instead of free-text prompts it takes **typed parameters** against a published contract — named operations, a JSON Schema for inputs, worked examples, per-operation approval gates, and (over MCP) the acting user's live credential status. The rule that prevents almost every tool failure: **fetch the contract before the first call to an unfamiliar tool — the contract IS the API documentation.** ## Prerequisites - Self-service `ozk_` key from **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`). - MCP: `https://mcp.plungeai.com/v1`. REST: `https://api.plungeai.com`. ## Discovery first Find the tool (`plungeai_list_agents {search}` / `GET /v1/discovery/search`, see `plungeai-discovery`), then fetch its contract: ```json plungeai_get_tool_contract {agent_id: "markitdown"} ``` ```bash curl -s https://api.plungeai.com/v1/tools/markitdown -H "Authorization: Bearer ozk_YOUR_KEY" ``` Read it in order: `operations` (pick by `purpose`; note `gated: true`), `inputSchema` (exact param shapes), `examples` (worked CNL), then — MCP contract only — the **Credentials** section (see below). ## Execute — MCP ```json plungeai_execute_tool { agent_id: "markitdown", operation: "convert", params: { file_data: "<base64 of the file>", file_name: "report.pdf" } } ``` Answers a structured outcome envelope over HTTP 200, always — `ok` \| `needs_input` \| `needs_connection` \| `needs_api_key` \| `needs_approval` \| `unavailable` \| `error`. Full parameter table and the outcome table — [`references/mcp-execute-tool.md`](/skills/plungeai-tools-connectors/references/mcp-execute-tool). ## Execute — REST ```bash curl -s -X POST https://api.plungeai.com/v1/tools/brave-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{"operation": "search", "params": {"query": "cloudflare workers pricing"}}' ``` Same fences, REST spelling: `403 refused` (fence — never retry), `404 unknown_tool`, `409 approval_required` (a dispatched run's own outcome paused for approval — approve out-of-band in Studio, then re-issue the identical request; REST has no continuation token like MCP's `plungeai_continue`), `422 invalid_params` (body carries `missing` + the full contract — self-correct and retry once). Full error catalogue, the 403 fence-vs-lifecycle distinction, streaming/format — [`references/rest-tools-plane.md`](/skills/plungeai-tools-connectors/references/rest-tools-plane) and [`references/contract-and-execution.md`](/skills/plungeai-tools-connectors/references/contract-and-execution). ## Connected accounts (credential status) The contract's Credentials section is LIVE per acting user: - `🔐 platform-managed` — nothing to connect. - `✅ connected as <email>` — call away. - `⚠️ NOT connected` / `expired — reconnect` — execution answers `needs_connection`/`needs_api_key` (MCP) or `424 connection_required` (REST) until the user connects it in a PlungeAI app (Studio → Connectors). Relay exactly what to connect; retry the identical call after. ## Why the fences exist Gated operations are the ones with real-world blast radius: money movement, outbound messages, irreversible mutations. **An unattended caller never fires them** — a human must be in the loop. `403`/`409`/`needs_approval` are correct behavior, not errors to engineer around: surface them, get the human decision, continue through the approval mechanism (`plungeai_continue` on MCP). A retried tool call re-fires the FULL operation — check execution history before re-firing anything non-idempotent. ## Gotchas - **Reserved param names** (`agent`, `type`, `id`, `operation`, `depth`, `user_id`, `executor_user_id`, `workflow`, `execution_id`) collide with the task envelope and are never forwardable — `needs_input`/`422` names them. - **A lone `prompt` on a multi-operation card runs the DEFAULT operation** and warns about it — if that's not what the user meant, re-call with an explicit `operation` + typed `params`. - **`gated: true` is refused regardless of operation wording** — rephrasing the prompt or switching styles to sneak past a fence never works. - **`409 approval_required` IS real on REST** — it fires when a dispatched run's own outcome comes back `needs_approval`, not from the pre-dispatch gated-verb/guarded-category fence (that fence runs in unattended mode on this route and always resolves to `403 refused` instead). Approve out-of-band, then re-issue the identical request. ## Related skills - `plungeai-discovery` — search, full cards, the contract fetch itself. - `plungeai-agents` — prompt-driven execution, `plungeai_get_result`. - `plungeai-models` — model/provider overrides, the money plane. - `plungeai-workflows` — put a tool's typed fields directly on a CNL task. - `plungeai-results-traces` — tracing an `execution_failed`/`upstream_error`. ## Reference pages <CardGroup cols={2}> <Card title="Tools — structured tool-agents and their contracts" icon="file-text" href="/skills/plungeai-tools-connectors/references/contract-and-execution"> A tool on PlungeAI is a structured agent: instead of free-text prompts it takes typed parameters against a published contract — named operations, a JSON… </Card> <Card title="Executing tools over MCP — execute_tool" icon="file-text" href="/skills/plungeai-tools-connectors/references/mcp-execute-tool"> Structured tool-agents (cards with a Parameters table — posting, document conversion, weather, data-table CRUD, calendar operations, payment actions) take… </Card> <Card title="Tools plane — /v1/tools" icon="file-text" href="/skills/plungeai-tools-connectors/references/rest-tools-plane"> Every active agent is also callable as a tool with a machine-checkable invocation contract. </Card> </CardGroup> # Tools — structured tool-agents and their contracts Source: https://docs-preview.plungeai.com/skills/plungeai-tools-connectors/references/contract-and-execution <!-- sources-of-truth: orchestration/api-gateway/openapi.ts, orchestration/mcp-gateway/server.ts, orchestration/mcp-gateway/tools.ts, core/core-base/tool-contract.ts, core/core-base/call-agent.ts | last-synced: 2026-09-24 (re-verified: reserved-param list against tool-contract.ts RESERVED_TASK_FIELDS, 409/403 fence behavior against call-agent.ts checkAgentCall unattended vs interactive branches, and routes/tools.ts execute handler — all match, no drift found) --> A **tool** on PlungeAI is a structured agent: instead of free-text prompts it takes **typed parameters** against a published contract — named operations, a JSON Schema for inputs, worked examples, and per-operation approval gates. Think of document converters, weather lookups, data-table CRUD, calendar operations, payment actions. The rule that prevents almost every tool failure: **fetch the contract before the first call to an unfamiliar tool. The contract IS the API documentation** — current, generated from the live card, and (over MCP) personalized with the acting user's credential status. ## The contract `GET /v1/tools/{id}` (One API) or `plungeai_get_tool_contract {agent_id}` (MCP): ```json { "agent_id": "markitdown", "name": "markitdown", "description": "Convert a document, image, audio file, or URL to markdown…", "operations": [ { "name": "convert", "purpose": "Convert a file or URL to markdown", "gated": false, "required_params": ["file_data", "file_name"] } ], "inputSchema": { "type": "object", "properties": { "…": {} } }, "examples": [ { "title": "Convert a PDF to markdown", "cnl": "…worked YAML…" } ], "output_type": "markdown" } ``` Read it in this order: 1. **`operations`** — pick the operation whose `purpose` matches the job. Note `gated: true`: that operation needs human approval (see fences below). 2. **`inputSchema`** — the exact parameter shapes. `required_params` per operation is the short list; the schema is the authority on types and enums. 3. **`examples`** — worked CNL YAML; each example also shows how the tool is used as a workflow task (the same fields go on a task next to `agent:` — see the `plungeai-workflows` skill). 4. **Credential status** (MCP contract only) — LIVE per-user: "platform-managed" means it just works; "connect Google first" means the call will return `needs_connection` until the user connects that credential in Studio. ## Discovery ```bash # List active tool-agents curl -s "https://api.plungeai.com/v1/tools?limit=50" \ -H "Authorization: Bearer ozk_YOUR_KEY" # → {tools: [Card…], count} ``` Or find by capability with the hybrid search (`GET /v1/discovery/search?q=…`) / `plungeai_list_agents {search}` — tools are agents; they appear in the same registry with a Parameters table on their card. ## Execution ### MCP: `plungeai_execute_tool` ``` plungeai_execute_tool { agent_id: "markitdown", operation: "convert", params: { file_data: "<base64 of the file>", file_name: "report.pdf" } } ``` Runs through the engine with full observability (an execution id you can trace). Long jobs: `mode: "async"` → poll `plungeai_get_workflow_status` → fetch with `plungeai_get_result`. Every call answers with a **structured outcome envelope over HTTP 200** — a blocked call is guidance, never a protocol error. The complete MCP status vocabulary: | Outcome | Meaning | Your move | |---|---|---| | `ok` | Result attached | Relay it verbatim | | `needs_input` | Missing/invalid fields; the outcome carries them + the schema | Fix exactly those fields; retry once | | `needs_connection` / `needs_api_key` | User credential missing | Tell the user exactly what to connect in the platform apps; retry after | | `needs_approval` | A gated/money operation paused the run (`⏸`) | Relay the approval block verbatim; only after the user explicitly approves, `plungeai_continue {approve: true}`; their "no"/changes go in `message` | | `unavailable` | Tool/dependency not live (or fenced off); alternatives listed | Pick an alternative or re-discover | | `error` | Downstream execution failed; the summary names the cause | Read it; inspect the trace (`plungeai-results-traces`); do not hammer-retry | There is no `refused` MCP status: MCP has an approval surface, so gated operations pause as `needs_approval` instead of being refused. `refused` is the One API's REST spelling of the fence (`403` below). ### One API: `POST /v1/tools/{id}/execute` ```bash curl -s -X POST https://api.plungeai.com/v1/tools/markitdown/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{ "operation": "convert", "params": { "file_data": "<base64 of the file>", "file_name": "report.pdf" } }' # 200 → {"ok": true, "content": "…", "outcome": "ok", "request_id": "…"} ``` `prompt` is accepted instead of `operation`/`params` for prompt-driven agents reached through this route — but if the card has a Parameters table, use typed params. HTTP status mapping (same fences, REST spelling): | Status | Code | Meaning | |---|---|---| | `403` | `refused` | Fence — gated/money operation refused unattended. Do not retry. | | `404` | `unknown_tool` | Id not in the live catalog — re-discover | | `409` | `approval_required` | The dispatched run's own outcome paused for approval (`needs_approval`) — real and reachable on this route. Approve out-of-band (Studio), then re-issue the identical request; the One API has no continuation token like MCP's `plungeai_continue`. | | `422` | `invalid_params` | Body carries the missing/reserved fields AND the contract — fix exactly those | | `502` | `execution_failed` | Downstream failure — inspect the trace (`plungeai-results-traces`) | ## Why the fences exist Gated operations are the ones with real-world blast radius: money movement, outbound messages, irreversible mutations. The platform's trust model is that **an unattended caller never fires them** — a human must be in the loop. `403`/`409` are therefore correct behavior, not errors to engineer around. Surface them, get the human decision, continue through the approval mechanism. Also remember: a retried tool call re-fires the FULL operation — if the side effect completed before the failure was reported, a retry duplicates it. When in doubt, check execution history (`plungeai_executions`) before re-firing anything non-idempotent. ## Tools inside workflows A structured tool-agent is used in CNL by putting its typed fields directly on the task, next to `agent:`: ```yaml - type: task id: convert agent: markitdown operation: convert file_data: "{input}" file_name: report.pdf ``` The contract's `examples[].cnl` show the canonical per-tool shapes. Everything else about composition is in the `plungeai-workflows` skill. ## Checklist 1. Contract fetched (first use) — operation picked by `purpose`, gates noted. 2. Params match `inputSchema` exactly — no extra prose fields. 3. Credential status green (MCP) or the user warned. 4. Gated op → plan for the approval pause; unattended REST cannot serve it. 5. Outcome remediation followed; no blind retries; no duplicate side effects. # Executing tools over MCP — execute_tool Source: https://docs-preview.plungeai.com/skills/plungeai-tools-connectors/references/mcp-execute-tool <!-- sources-of-truth: orchestration/mcp-gateway/tools.ts, orchestration/mcp-gateway/server.ts, orchestration/mcp-gateway/tool-exec.ts, orchestration/mcp-gateway/registry-cards.ts, orchestration/mcp-gateway/tool-outcome.ts, orchestration/mcp-gateway/credential-preflight.ts | last-synced: 2026-09-24 (execute_tool half of the original discovery-and-execution.md; the list_agents/get_tool_contract half lives in plungeai-discovery, the execute_agent/get_result half lives in plungeai-agents. Re-verified ExecuteToolSchema + reserved-param list against tool-exec.ts/tool-contract.ts — all match, no drift found) --> Structured tool-agents (cards with a Parameters table — posting, document conversion, weather, data-table CRUD, calendar operations, payment actions) take typed fields against a published contract, not prose. Always fetch the contract first (`plungeai_get_tool_contract`, see `plungeai-discovery`) — the contract IS the API documentation, generated live from the card and personalized with the acting user's credential status. ## plungeai_execute_tool **Purpose:** run one structured tool-agent directly with typed params, through the same engine pipeline as every other execution (history, results, HITL all included). **Parameters** | Param | Type | Notes | |---|---|---| | `agent_id` | string, required | From a live search (`plungeai_list_agents`). | | `operation` | string ≤128 | One of the contract's operations. Also auto-filled into the card's selector param (`action`/`op`/`operationType`) when the card reads its operation from a param — so passing `operation` alone is safe. | | `params` | object | Typed fields per the contract's JSON Schema. | | `prompt` | string | Prose fallback. On a card whose requireds resolve to exactly ONE free-text param, a lone prompt is mapped into it (visibly, with a warning). Never mapped into selectors, enums, or URL params. | | `mode` | `sync` \| `async` | Async returns an execution id to poll. | | `format` | `markdown` \| `json` | Response serialization; default markdown. | **Example** ```json {"user_request": "what's the weather in Lisbon this weekend?", "agent_id": "weather-agent", "operation": "forecast", "params": {"location": "Lisbon", "days": 3}} ``` **Returns:** the outcome envelope, always (never a raw error): | Status | Meaning → your move | |---|---| | `ok` | Result markdown + execution-id footer (+ any ⚠️ warnings, e.g. "prose mapped"). Relay verbatim. | | `needs_input` | Missing/invalid fields; `missing[]` + the full contract ride along so you can fix the SAME call without a second lookup. Nothing was executed. | | `needs_connection` / `needs_api_key` | The USER must connect a service or save a key in a PlungeAI app. Relay the instructions, wait for them, retry the identical call. Caught pre-flight when possible — before a run exists. | | `needs_approval` | ⏸ gated operation paused mid-run. Relay verbatim; `plungeai_continue` after the user decides. | | `unavailable` | Agent refused (unknown/inactive) or temporarily down — real alternatives included. Nothing was executed. | | `error` | Terminal failure with a reason; follow the remediation (often `retry_with {mode: "async"}` for timeouts). | **Failures & fixes** - Reserved param names (colliding with the task envelope) → `needs_input` naming them; rename/drop those keys. The reserved names: `agent`, `type`, `id`, `operation`, `depth`, `user_id`, `executor_user_id`, `workflow`, `execution_id`. - Prose prompt + no `operation` on a multi-operation card → the run executes the card's DEFAULT operation and says so in a warning. If that is not what the user meant, re-call with an explicit `operation` + typed params. - Gated operations are not refused up front — they pause (`needs_approval`). That pause is a trust fence: surface it, never bypass it. ## Connected accounts (credential status) The contract's Credentials section (fetched via `plungeai_get_tool_contract`, see `plungeai-discovery`) is LIVE per acting user: - `🔐 platform-managed` — nothing to connect; just call. - `✅ connected as <email>` — the user's OAuth/API-key connection is live; call away. - `⚠️ NOT connected` / `expired — reconnect` — `plungeai_execute_tool` will answer `needs_connection` / `needs_api_key` until the user connects that credential in a PlungeAI app (Studio → Connectors). Relay exactly what to connect; do not retry until they have. The credential-status RPC runs speculatively in parallel with the card fetch on `plungeai_get_tool_contract`, so the contract call itself carries this status — no separate lookup needed before your first `execute_tool` attempt. ## Putting it together — the canonical multi-step run ``` 1. plungeai_list_agents {search: "convert pdf to markdown"} → markitdown 2. plungeai_get_tool_contract {agent_id: "markitdown"} → schema; credentials 🔐 platform-managed 3. plungeai_execute_tool {agent_id: "markitdown", operation: "convert", params: {file_data: "<base64 of the file>", file_name: "report.pdf", format: "markdown"}, mode: "async"} → execution_id E 4. plungeai_get_workflow_status {execution_id: E} → running → completed 5. plungeai_get_result {execution_id: E} → relay verbatim (see plungeai-agents) ``` Note how step 3 follows step 2's contract: `convert` requires `file_data` (base64-encoded content) and `file_name` for uploaded files (a `url` param is also accepted for web pages/YouTube/Wikipedia, but a file already in hand goes through `file_data`). Skip step 2 only for agents whose contract you fetched earlier in the same conversation. Skip steps 4–5 in sync mode — the result comes back in the execute call itself. # Tools plane — /v1/tools Source: https://docs-preview.plungeai.com/skills/plungeai-tools-connectors/references/rest-tools-plane <!-- sources-of-truth: orchestration/api-gateway/openapi.ts, docs/ONE-API-DEVELOPER-GUIDE-2.0.md | last-synced: 2026-09-24 (re-verified against orchestration/api-gateway/routes/tools.ts, _util.ts, core/core-base/call-agent.ts; fixed a stale "Settings → Integrations / Connectors" UI label to the real one, Studio → Connectors, per apps/ocean-studio/src/components/connectors/) --> Every active agent is also callable as a **tool** with a machine-checkable invocation contract. The flow is always: **discover → inspect the contract → execute**. This plane runs the platform's trust fence — gated and money operations refuse unattended execution by design. Auth: `Authorization: Bearer ozk_YOUR_KEY` on every route here. ## GET /v1/tools — list active tool-agents Query params: `limit` (default 50, max 100), `offset` (default 0). ```bash curl -s "https://api.plungeai.com/v1/tools?limit=2" \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "tools": [ { "id": "brave-agent", "name": "Brave Search", "type": "agent", "category": "search", "status": "active", "description": "Web search via Brave", "tags": ["search"] }, { "id": "pdf-agent", "name": "PDF Agent", "type": "agent", "category": "documents", "status": "active", "description": "Convert and extract PDFs", "tags": ["pdf"] } ], "count": 2 } ``` `count` is the returned page's length, not the catalog total — page until a short page, never until `offset >= count`. A failed registry hop returns `502 upstream_error`. ## GET /v1/tools/{id} — the invocation contract Fetch this **before the first execute** of any unfamiliar tool. The contract tells you the operations, which are gated, the required params, the JSON Schema for inputs, and worked examples. ```bash curl -s https://api.plungeai.com/v1/tools/brave-agent \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "agent_id": "brave-agent", "name": "Brave Search", "description": "Web search via the Brave Search API", "operations": [ { "name": "search", "purpose": "Run a web search", "gated": false, "required_params": ["query"] }, { "name": "news", "purpose": "Search recent news", "gated": false, "required_params": ["query"] } ], "inputSchema": { "type": "object", "properties": { "query": { "type": "string" }, "count": { "type": "integer" } } }, "examples": [ { "title": "Basic web search", "cnl": "operation: search\nparams:\n query: cloudflare workers" } ], "output_type": "markdown" } ``` 404 → `{"error":{"code":"unknown_tool","message":"..."}}` — the id isn't an active tool. Re-discover via `GET /v1/tools` or discovery search. `gated: true` on an operation means executing it unattended is refused with **403 `refused`** by this route's pre-dispatch fence (`checkAgentCall` runs in `'unattended'` mode here, which always resolves a gated-verb/guarded- category hit to a refusal, never a pause). `409 approval_required` is a *different*, real code path on this same route — see the fence section below. ## POST /v1/tools/{id}/execute — execute an operation Body — two styles, both valid: | Field | Type | Notes | |---|---|---| | `operation` | string | Operation name from the contract | | `params` | object | Params per the contract's `inputSchema` | | `prompt` | string | Free-text alternative for prompt-driven tools | | `format` | string | Response negotiation: `json` (default) \| `yaml` \| `markdown` \| `text` — same values as an `Accept` header or the request `Content-Type` mirror | Validation rules ("reserved" = param names colliding with engine task-envelope fields — `agent`, `type`, `id`, `operation`, `depth`, `user_id`, `executor_user_id`, `workflow`, `execution_id` — never forwardable): - Reserved param names → 422, always. - Missing required params → 422 **only when no `prompt` is present** — a prose prompt satisfies prompt-capable agents, so a prompt-style call skips param validation entirely. The trust fence still runs either way. Structured style (preferred when the contract defines operations): ```bash curl -s -X POST https://api.plungeai.com/v1/tools/brave-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"operation": "search", "params": {"query": "cloudflare workers pricing"}}' ``` Prompt style: ```bash curl -s -X POST https://api.plungeai.com/v1/tools/brave-agent/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "search: cloudflare workers pricing"}' ``` Success — HTTP 200: ```json { "ok": true, "content": "# Web Search: cloudflare workers pricing\n\n1. ...", "outcome": "success", "request_id": "00000000-0000-4000-8000-000000000004" } ``` ## Error semantics — features, not failures | Status | Code | Meaning | Correct handling | |---|---|---|---| | 400 | `invalid_format` | `format` isn't one of `json`/`yaml`/`markdown`/`text` | Fix the field | | 404 | `unknown_tool` | No such active tool | Re-discover the id | | 422 | `invalid_params` | Contract violation — response body carries `missing`, `reserved`, `warnings`, **and the full contract** | Self-correct from the echoed contract; retry once with fixed params | | 403 | `refused` (fence) | Gated operation, or payment/blockchain-category agent — never callable unattended | **FINAL. Surface verbatim. NEVER retry, rephrase, or work around** | | 403 | `refused` (lifecycle) | Parked agent (`status:developing/development/developed`) or unknown card — the `reason` says which | Re-discover via `GET /v1/tools` / discovery search | | 409 | `approval_required` | The dispatched run's own outcome came back `needs_approval` (mapped 1:1 via the outcome→HTTP table — guide 3.0 §13.3/§13.5). NOT produced by the pre-dispatch gated-verb/guarded-category fence, which always resolves to 403 on this route (see below) | Approve out-of-band (Studio / an attended surface), then re-issue the identical request | | 409 | `duplicate_execution_id` | The `x-trace-id` header was already used by an earlier run | Send a fresh UUID | | 413 | `payload_too_large` | Body over 1 MiB (`MAX_REQUEST_SIZE`) | Shrink the payload (e.g. stream large files through a URL param instead of inline `file_data`) | | 424 | `connection_required` / `credential_required` | The agent needs a connection or key the acting user hasn't set up | Tell the user what to connect (Studio → Connectors); retry after | | 429 | `rate_limited` | Per-key limiter — `Retry-After` header | Back off and retry | | 502 | `execution_failed` | The dispatched agent failed — body carries `outcome`, `detail`, `content` | Act on `outcome` (`needs_input`, `needs_connection`, …) before blind-retrying; one retry only for transient outcomes | | 502 | `upstream_error` | Registry/engine hop threw (any route in this plane) | One retry with backoff | | 503 | `agent_unavailable` | Agent temporarily down | Retry later or pick an alternative | ### 422 example — the contract comes back to you ```json { "error": { "code": "invalid_params", "message": "params failed card validation", "missing": ["query"], "reserved": [], "warnings": [], "contract": { "agent_id": "brave-agent", "operations": [ "..." ] } } } ``` Generated code should parse `missing` and the embedded `contract`, repair the body, and retry exactly once. If the second attempt also 422s, stop and report. ### 403 — the trust fence, and how to tell refusals apart **Fence refusals are FINAL.** The gated-verb floor (`buy`, `purchase`, `fetch_paid`, `send`, `transfer`, `pay`, `send_payment`, `withdraw`, `shop`), operations the card tags `gated:`, and payment/blockchain-category agents (refused **regardless of operation** on this surface): ```json { "error": { "code": "refused", "message": "operation \"transfer\" on x is gated (outward/irreversible) and requires human approval — not available in unattended runs." } } ``` Do not loop, do not reword the prompt to sneak past the fence, do not switch to the prompt style to avoid the operation gate. Tell the user what was refused and why; approvals happen on attended surfaces (Ocean Studio / apps), not through this API. **Lifecycle refusals are not final** — the same 403 `refused` code also covers parked agents ("parked (status:…) — not callable. Use registry search to find an active alternative.") and ids with no registry card. The `reason` string distinguishes them; the remedy is re-discovery, not surrender. **`409 approval_required` is real and reachable on this route** — but not from the check above. `POST /v1/tools/{id}/execute` calls the shared gated-verb/guarded-category fence (`checkAgentCall`, `core/core-base/ call-agent.ts`) in `'unattended'` mode, and in that mode every branch that could otherwise pause for approval (a guarded payment/blockchain category with no recognizable operation, or a gated verb) resolves to `403 refused` instead — `approval_required` is only returned by that function in `'interactive'` mode, which this route never uses. The 409 you actually see on this plane comes from a **different** source: the dispatched run's own outcome. If the downstream agent/tool run itself pauses mid-execution (outcome `needs_approval` — the same status MCP surfaces as a ⏸ block), the outcome→HTTP mapping (guide 3.0 §13.3, "Trust fence" §13.5) turns that into `409 approval_required` here too. Handling: **approve out-of-band** (Studio or another attended surface), **then re-issue the identical request** — the One API has no continuation token like MCP's `plungeai_continue`, so you resend rather than resume. ## Tools vs agents — which plane to call - `/v1/tools/:id/execute` — structured, contract-validated, fenced. Use when you know the operation and params (typical for generated app code). - `/v1/agents/:id/execute` — free prompt, sync/async semantics, no operation contract. Use for open-ended instructions to LLM-driven agents. Same underlying agents, different invocation disciplines. # plungeai-workflows Source: https://docs-preview.plungeai.com/skills/plungeai-workflows Build, validate, test, and save PlungeAI (Ocean Studio) workflows in CNL YAML. Use when the user wants to create or edit a PlungeAI/Ocean workflow, orchestrate PlungeAI agents, write CNL YAML, run a multi-agent pipeline on PlungeAI, or turn research in this chat into a saved Studio workflow. Triggers: "PlungeAI workflow", "Ocean Studio workflow", "CNL", "build a workflow", "save this as a workflow", "plungeai agents". [Download zip](https://skills.plungeai.com/plungeai-workflows.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-workflows/SKILL.md) Author CNL workflow YAML for the PlungeAI platform, prove it works, and save it so it appears in Ocean Studio and every connected app. ## Prerequisites (check first, once) - Preferred: the `plungeai` MCP server is connected (tools named `plungeai_*` are available). Confirm identity with `plungeai_whoami`. - Otherwise: you can still author correct YAML and hand the user a paste-ready block (see [`references/channels.md`](/skills/plungeai-workflows/references/channels), Channels 2-3). ## The loop 1. **Understand the goal.** One sentence: input → steps → deliverable. Ask only if the goal is genuinely ambiguous. 2. **Discover agents — never from memory.** `plungeai_list_agents {search: "<capability in plain words>"}` per capability. Take ids verbatim from results (kebab-case). Unknown or inactive ids are refused at execution. Fetch a full card with `{agent_id}` before using an unfamiliar agent — cards carry parameters and "Not for → use X instead" redirects. 3. **Author the YAML.** Load [`references/cnl-spec.md`](/skills/plungeai-workflows/references/cnl-spec) and pick a shape from [`references/recipes.md`](/skills/plungeai-workflows/references/recipes). Independent steps go in `parallel`; chained steps in `sequential` with `{data:task_id}`; goal-driven open-ended work is ONE `type: harness` task, not many small tasks. Long prompts use block scalars (`prompt: |`) — never hard-wrap a value. 4. **Test ad-hoc BEFORE saving.** `plungeai_execute_workflow {workflow_yaml, input}` (`mode: "async"` + `plungeai_get_workflow_status` for long runs). Read the actual output — does it satisfy the user's goal? Iterate the YAML, not the save. 5. **Save.** `plungeai_workflow {action: "create", name, yaml, description}`. The platform re-validates server-side; a refusal lists field errors — fix exactly those and retry. On success it syncs live to Studio and peer apps. Iterations on a saved workflow: `action: "update"` (plus `"save_version"` before big changes). 6. **Learn-back (offer it).** If real research happened in this chat, offer: `plungeai_learn {source: "<distilled findings>"}` to save it as a reusable platform skill that future runs can inject. ## Hard rules (the top causes of refused YAML) - Agent ids ONLY from a live `plungeai_list_agents` search. `brave-agent`, never `brave-search`. - These do NOT exist: `$variable`, `depends_on`, `outputs:`, `parallel: true`, `schedule:` (scheduling is configured in Studio, not YAML). - `parallel` / `sequential` / `batch` / `dynamic` / `debate` / `validate` blocks never carry `agent:` — agents go on the inner tasks. - `type: task` reads `prompt:` (or `query:`) — not input/instructions/message. `goal:` belongs to `type: harness` only. - Every `id` unique; data flows automatically — never hand-wire results. - Search agents (brave-agent, tavily-agent, …) take SEARCH TERMS — short queries, not instructions. Synthesis, analysis, and "based on the research above…" prompts belong on `llm-agent`. ## When something fails - **create refused** → the message names field + problem; fix exactly that, retry once. - **"agent not active/unknown"** → re-search the registry; the catalog is live. - **execution succeeded but output is wrong** → improve prompts/structure and re-run ad-hoc; only save after the output is right. - **no MCP tools available** → Channels 2-3 in [`references/channels.md`](/skills/plungeai-workflows/references/channels). ## References (load on demand) - [`references/cnl-spec.md`](/skills/plungeai-workflows/references/cnl-spec) — full CNL v6 reference (all 10 task types, validation errors) - [`references/recipes.md`](/skills/plungeai-workflows/references/recipes) — canonical patterns + when to use each - [`references/channels.md`](/skills/plungeai-workflows/references/channels) — MCP (`https://mcp.plungeai.com/v1`) / Studio paste / raw HTTP API - `examples/*.yaml` — six validated, runnable workflows ## More - [`references/overview.md`](/skills/plungeai-workflows/references/overview) — the platform-level view: parallelism facts (measured, not guessed), placeholders and date tokens, execution/results/ follow-up semantics, failure semantics. - [`references/api.md`](/skills/plungeai-workflows/references/api) — the One API `/v1/workflows/*` HTTP surface: inline vs saved execution, SSE streaming events, result redemption, cancel, trace correlation, legacy aliases. - [`references/mcp.md`](/skills/plungeai-workflows/references/mcp) — the full MCP tool set for workflows: `plungeai_execute_workflow`, `plungeai_get_workflow_status`, `plungeai_list_workflows`, `plungeai_workflow` (CRUD + versioning), `plungeai_build_workflow`, `plungeai_executions`, and `plungeai_templates` (`action: "use"` — instantiating a gallery template as a workflow; browsing is `plungeai-discovery`'s). ## Reference pages <CardGroup cols={2}> <Card title="Workflows plane — /v1/workflows" icon="file-text" href="/skills/plungeai-workflows/references/api"> Run multi-agent CNL workflows: inline (send the workflow document in the request), saved (reference a workflow id saved in Ocean Studio), each with an… </Card> <Card title="Getting a workflow into PlungeAI — three channels" icon="file-text" href="/skills/plungeai-workflows/references/channels"> Connect once (self-service ozk key from Dashboard → One API → Keys, https://dashboard.plungeai.com): </Card> <Card title="CNL Workflow Reference (engine v6) — PlungeAI" icon="file-text" href="/skills/plungeai-workflows/references/cnl-spec"> CNL (Cognitive Natural Language) is PlungeAI's YAML workflow language: you declare tasks and how they compose (parallel, sequential, batch, debate, harness… </Card> <Card title="Workflows — execute_workflow, get_workflow_status, list_workflows, workflow, build_workflow, executions" icon="file-text" href="/skills/plungeai-workflows/references/mcp"> Workflows are CNL YAML run by the platform engine. </Card> <Card title="Workflows — CNL orchestration: what it is and how to run it" icon="file-text" href="/skills/plungeai-workflows/references/overview"> A workflow is a YAML document (CNL — Cognitive Natural Language) that the engine executes as a DAG of agent calls: parallel fan-out, sequential pipelines… </Card> <Card title="CNL recipes — pick the shape, then adapt" icon="file-text" href="/skills/plungeai-workflows/references/recipes"> Full runnable versions live in examples/. Two composition rules apply to all of them: </Card> </CardGroup> ## Examples <AccordionGroup> <Accordion title="01-simple-search.yaml"> ```yaml 01-simple-search.yaml name: "Simple Single Task" version: "2.0.0" description: "Single search task — the smallest valid CNL workflow." tasks: - type: "task" id: "single_task" agent: brave-agent prompt: "simple search test" input: "electric vehicles 2026" ``` </Accordion> <Accordion title="02-parallel-research.yaml"> ```yaml 02-parallel-research.yaml name: "Parallel Research With Synthesis" version: "2.0.0" description: "Three parallel searches from different engines, then LLM synthesis. The most common production pattern." tasks: - type: "parallel" id: "research_phase" subtasks: - type: "task" id: "brave_search" agent: brave-agent prompt: "{input} — latest news, trends, and analysis" - type: "task" id: "tavily_research" agent: tavily-agent prompt: "{input} — cited sources and detailed reporting from the last 12 months" - type: "task" id: "exa_deep" agent: exa-agent operationType: "search" prompt: "{input} — academic papers, institutional research, and expert analyses" - type: "task" id: "synthesis" agent: llm-agent prompt: | Synthesize the parallel research into a comprehensive report on {input}. Sources: Brave: {data:brave_search} Tavily: {data:tavily_research} Exa: {data:exa_deep} Identify common themes, contradictions, and the three strongest insights. input: "quantum computing commercial applications" ``` </Accordion> <Accordion title="03-hierarchical.yaml"> ```yaml 03-hierarchical.yaml name: "3-Level Hierarchical Nesting" version: "2.0.0" description: "parallel → sequential → parallel nesting. Demonstrates unlimited nesting depth with data flowing automatically." tasks: - type: "parallel" id: "level_1_parallel" subtasks: - type: "task" id: "simple_task" agent: brave-agent prompt: "{input} — quick overview" - type: "sequential" id: "level_2_sequential" subtasks: - type: "task" id: "deep_search" agent: tavily-agent prompt: "{input} — deep research with citations" - type: "parallel" id: "level_3_parallel" subtasks: - type: "task" id: "business_angle" agent: llm-agent prompt: "From the research, extract business implications for {input}" - type: "task" id: "technical_angle" agent: llm-agent prompt: "From the research, extract technical implications for {input}" - type: "task" id: "final_report" agent: llm-agent prompt: "Combine all prior branches into a comprehensive report on {input}." input: "autonomous vehicle regulation" ``` </Accordion> <Accordion title="04-validate-consensus.yaml"> ```yaml 04-validate-consensus.yaml workflow: name: "Consensus Validation With 3 Validators" version: "2.0.0" description: "Three LLM validators run in consensus on a single piece of content. Use when correctness must be triple-checked before publishing." tasks: - type: validate id: fact_check aggregation: consensus validators: - agent: llm-agent validation_rule: "Check if the numerical claims are plausible and internally consistent" - agent: llm-agent validation_rule: "Check for logical consistency — identify any contradictions" - agent: llm-agent validation_rule: "Check completeness — are all key financial metrics covered" success_criteria: "Content must be factually plausible, logically consistent, and comprehensive" input: "Tesla reported Q4 2025 revenue of $25.7B. The automotive segment contributed $21.3B while energy generation and storage added $2.8B. Gross margins improved to 19.8% from 17.6% year-over-year. The company delivered 495,000 vehicles in Q4, a 12% increase from Q3." ``` </Accordion> <Accordion title="05-batch-items.yaml"> ```yaml 05-batch-items.yaml name: "Per-Item Batch Pipeline" version: "1.0.0" description: "Run the same two-step pipeline for every item in a list, then roll up." tasks: - type: "batch" id: "per_company" items: - "Cloudflare" - "Vercel" - "Fly.io" tasks: - type: "task" id: "research" agent: brave-agent prompt: "{item} — company overview, funding, latest news" - type: "task" id: "brief" agent: llm-agent prompt: "From the research above, write a 5-bullet analyst brief on {item}" - type: "task" id: "rollup" agent: llm-agent prompt: "Combine the briefs into one comparison table: {data:per_company}" input: "edge platforms" ``` </Accordion> <Accordion title="06-harness-mission.yaml"> ```yaml 06-harness-mission.yaml name: "Bounded Research Mission" version: "1.0.0" description: "A goal-driven harness run with an inline mission, effort preset, and turn cap." 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 success_criteria: - "5 vendors named with pricing" - "every claim has a source URL" - type: "output" id: "deliver" format: "markdown" input: "workflow orchestration platforms" ``` </Accordion> </AccordionGroup> # Workflows plane — /v1/workflows Source: https://docs-preview.plungeai.com/skills/plungeai-workflows/references/api <!-- sources-of-truth: orchestration/api-gateway/openapi.ts, orchestration/api-gateway/routes/workflows.ts, docs/ONE-API-DEVELOPER-GUIDE-2.0.md | last-synced: 2026-09-23 --> Run multi-agent CNL workflows: **inline** (send the workflow document in the request), **saved** (reference a workflow id saved in Ocean Studio), each with an optional **SSE streaming** variant, plus a results-redemption route. Auth: `Authorization: Bearer ozk_YOUR_KEY` on every route here. Tenancy is automatic — the engine keys every run to your key's identity; saved workflows and results resolve only within it. Authoring CNL YAML itself (task types, `parallel`/`sequential`, harness missions) is this `plungeai-workflows` skill's job; this file covers the HTTP surface for executing it. ## POST /v1/workflows/execute — inline execution Two body formats: **JSON** — `{"workflow": <object or YAML string>, "input"?: string, "inputs"?: object}`: ```bash curl -s -X POST https://api.plungeai.com/v1/workflows/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "workflow": { "name": "demo", "tasks": [ {"type": "task", "id": "t1", "agent": "llm-agent", "prompt": "Say: ok"} ] }, "input": "x" }' ``` **Raw YAML** — send the whole workflow document as the body with `Content-Type: text/yaml`: ```bash curl -s -X POST https://api.plungeai.com/v1/workflows/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: text/yaml" \ --data-binary @- <<'YAML' workflow: name: demo tasks: - type: task id: t1 agent: llm-agent prompt: "Say: ok" YAML ``` Response — HTTP 200 (an **acknowledgement + pointer**, not the content): ```json { "success": true, "workflow_id": "00000000-0000-4000-8000-000000000001", "final_task_id": "t1", "request_id": "00000000-0000-4000-8000-000000000004" } ``` Redeem the actual output with `workflow_id` + `final_task_id` (below). For a multi-task workflow, `final_task_id` is the last task — intermediate task results are redeemable by their own task ids. Errors: `400 missing_workflow` (no `workflow` in a JSON body / empty YAML), `502 engine_error` (engine reported failure; message included), `404 workflow_not_found` — yes, on the **inline** route too: any engine failure whose message contains "not found" (typically an unknown agent id → "Service binding not found") maps to 404. Re-discover the agent id; don't hunt for a missing saved workflow. ## POST /v1/workflows/{id}/execute — saved workflow Runs a workflow saved under your account (the id shown in Ocean Studio). Body is optional: `{"input"?: string, "inputs"?: object}`. ```bash curl -s -X POST https://api.plungeai.com/v1/workflows/wf-morning-brief/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"input": "today"}' ``` ```json { "success": true, "workflow_id": "00000000-0000-4000-8000-000000000001", "final_task_id": "t3", "request_id": "..." } ``` Errors: `404 workflow_not_found` (no such id under your identity — list your saved workflows in Studio, or re-check the id), `502 engine_error`. ## SSE streaming — live workflow events Two variants, same event stream: - `POST /v1/workflows/{id}/execute-stream` — saved workflow (in the OpenAPI spec) - `POST /v1/workflows/execute-stream` — inline body, same formats as `/v1/workflows/execute`, fully documented in the OpenAPI spec (`orchestration/api-gateway/openapi.ts`) alongside the saved-workflow variant. Caveat: this inline variant forwards `input` but **silently drops `inputs`** (the JSON branch never reads `body.inputs`, unlike the YAML branch which does — `orchestration/api-gateway/routes/workflows.ts`) — need multi-input? Use `/v1/workflows/execute` or `/v1/workflows/{id}/execute-stream` (both forward `inputs`). ```bash curl -N -X POST https://api.plungeai.com/v1/workflows/wf-morning-brief/execute-stream \ -H "Authorization: Bearer ozk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"input": "today"}' ``` Response is `text/event-stream` with **named events** — each frame is `event: <type>` + `data: <json>`, and the data payload always carries `{workflow_id, execution_id, timestamp, type, data, elapsed_ms, duration_ms?}` (the event-specific fields live under `data`). Event sequence: ``` request_received → workflow_loaded → workflow_started → task_dispatched → task_completed (per task) → heartbeat (every ~25s during a task >20s — expect it, or idle timeouts will kill long streams) → workflow_completed (success only; execution summary + metrics) → workflow_result (terminal, ALWAYS check its success field) ``` On failure the engine emits `workflow_error` (error + progress counters) and the terminal `workflow_result` carries `success: false` + `error` — code that only checks for the `workflow_result` event name reports failed runs as done. Other event types appear for the matching task types (`parallel_start`, `batch_progress`, `debate_*`, …) — switch on the ones you need, ignore the rest. A body the engine can't parse returns **HTTP 400 whose body is itself an SSE `error` event** — check the status before treating the body as a stream. Consume with any SSE client (`EventSource` won't do — it's a POST; use `fetch` + a stream reader in JS, or `curl -N` / `httpx.stream` elsewhere) and parse the `event:` lines, not just `data:` lines. The stream is pass-through and unbuffered; `x-request-id` is stamped on the response headers. Don't rely on a dropped stream's run surviving — the engine runs the workflow inside the stream; for durability use `/v1/workflows/execute` + the results route. ## GET /v1/workflows/results/{workflowId}/{taskId} — redeem a task result ```bash curl -s https://api.plungeai.com/v1/workflows/results/00000000-0000-4000-8000-000000000005/t1 \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` Ready — HTTP 200: ```json { "content": "ok", "content_type": "text/plain", "workflow_id": "00000000-0000-4000-8000-000000000001", "task_id": "t1" } ``` Not ready — HTTP 404 `{"error":{"code":"not_ready",...}}`. Poll with backoff (2s+, growing); `not_ready` while a workflow runs is normal. ## POST /v1/workflows/executions/{id}/cancel — cancel a running execution Cooperative cancel: writes the SharedMemory cancel marker the engine and agent loops poll at their next turn/tool boundary, then stamps the execution row `cancelled`. `{id}` is the execution id — the same value returned as `workflow_id` from `/v1/workflows/execute` (or the `x-trace-id` you sent on that call). Since `/v1/workflows/execute` is synchronous, send the cancel from a second connection while the first is still running. ```bash curl -s -X POST https://api.plungeai.com/v1/workflows/executions/00000000-0000-4000-8000-000000000005/cancel \ -H "Authorization: Bearer ozk_YOUR_KEY" ``` ```json { "success": true, "cancelled": "00000000-0000-4000-8000-000000000005", "markers": ["00000000-0000-4000-8000-000000000005"] } ``` Errors: `404 not_found` (no such execution under your identity — wrong owner never confirms the execution exists), `409 not_running` (already finished or already cancelled). ## Fire-and-redeem pattern (Python) ```python import time, requests BASE = "https://api.plungeai.com" H = {"Authorization": "Bearer ozk_YOUR_KEY"} ack = requests.post(f"{BASE}/v1/workflows/execute", headers=H, json={ "workflow": {"name": "demo", "tasks": [ {"type": "task", "id": "t1", "agent": "llm-agent", "prompt": "Say: ok"}]}, }).json() wf, task = ack["workflow_id"], ack["final_task_id"] for i in range(1, 9): r = requests.get(f"{BASE}/v1/workflows/results/{wf}/{task}", headers=H) if r.status_code == 200: print(r.json()["content"]); break time.sleep(2 * i) ``` ## Trace correlation Send `x-trace-id: <your-id>` on any execute call; every engine span of the run (dispatches, completions, the result) lands under that id at `GET /v1/traces/<your-id>` — see `plungeai-results-traces`. ## Legacy aliases (deprecated — do not use in new code) `POST /v1/execute`, `POST /v1/cnl/execute`, `POST /v1/cnl/execute-stream` are pre-router aliases of the inline workflow handlers, kept so old integrations don't break. Same auth, same bodies, same responses. New and generated code targets `/v1/workflows/*` only. # Getting a workflow into PlungeAI — three channels Source: https://docs-preview.plungeai.com/skills/plungeai-workflows/references/channels <!-- sources-of-truth: orchestration/mcp-gateway/tools.ts, orchestration/api-gateway/openapi.ts | last-synced: 2026-09-24 --> ## Channel 1 (preferred): PlungeAI MCP server Connect once (self-service `ozk_` key from **Dashboard → One API → Keys**, `https://dashboard.plungeai.com`): ```bash claude mcp add --transport http plungeai https://mcp.plungeai.com/v1 \ --header "Authorization: Bearer ozk_YOUR_KEY" ``` Other MCP clients (Claude Desktop, Cursor, …) use the `mcpServers` JSON form: ```json { "mcpServers": { "plungeai": { "command": "npx", "args": [ "mcp-remote", "https://mcp.plungeai.com/v1", "--header", "Authorization: Bearer ozk_YOUR_KEY" ] } } } ``` Then the whole loop is tool calls — no copy-paste: 1. `plungeai_list_agents {search: "<capability in plain words>"}` — hybrid semantic search over the live catalog. Take agent ids ONLY from results; fetch a full card with `{agent_id}` before using an unfamiliar agent (cards carry parameters and "Not for → use X instead" redirects). 2. `plungeai_execute_workflow {workflow_yaml: "<draft>", input: "..."}` — test ad-hoc before saving. Use `mode: "async"` + `plungeai_get_workflow_status` for runs longer than ~3 minutes. 3. `plungeai_workflow {action: "create", name, yaml, description}` — the platform re-validates server-side, then saves and syncs live to Studio and peer apps. A refusal lists field-level errors — fix exactly those and retry. **This is your final validation step.** 4. `plungeai_workflow {action: "save_version"}` before big edits; `action: "update"` to iterate. 5. `plungeai_learn {source: "<distilled findings>"}` — save research from this chat as a reusable platform skill. ## Channel 2: paste into Ocean Studio No MCP server? Produce the final YAML in a fenced block for the user. In Ocean Studio: open (or create) the workflow and switch to the **Code** tab → paste the YAML → the editor offers **Validate YAML Syntax** and **Format YAML** → save. Errors surface inline. ## Channel 3: direct HTTP API (advanced) Same gateway, raw MCP JSON-RPC over HTTP. Get a self-service `ozk_` key from **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`). ```bash # list available tools curl -s https://mcp.plungeai.com/v1 \ -H "Authorization: Bearer ozk_YOUR_KEY" -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # execute an ad-hoc workflow (YAML goes in as a JSON string) curl -s https://mcp.plungeai.com/v1 \ -H "Authorization: Bearer ozk_YOUR_KEY" -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"plungeai_execute_workflow","arguments":{"workflow_yaml":"name: quick\ntasks:\n - agent: brave-agent\n prompt: \"{input}\"\n","input":"latest AI news"}}}' ``` Create/save is the same shape with `"name":"plungeai_workflow"`, `"arguments":{"action":"create","name":"…","yaml":"…"}`. `X-API-Key: ozk_YOUR_KEY` works as an alternative header. Rate limits by tier: free 30/min, pro 100/min, enterprise 300/min. # CNL Workflow Reference (engine v6) — PlungeAI Source: https://docs-preview.plungeai.com/skills/plungeai-workflows/references/cnl-spec <!-- sources-of-truth: orchestration/cnl-engine/schema-types.ts, orchestration/cnl-engine/validate.ts | last-synced: 2026-09-24 --> 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** ```yaml 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** ```yaml 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`). ```yaml - 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`. ```yaml - 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`): | Field | Meaning | |---|---| | `mission` | Standing purpose → system-prompt frame (required in object form) | | `persona` | Persona / digital-twin id — one voice per run (single string) | | `skills` | Skill ids, array — injected eagerly (budget-capped), rest loadable in-loop | | `experts` | Expert/specialist ids, array — labeled context sections | | `backgrounds` | Always-on ambient context card ids, array | | `plugins` | Plugin bundle ids, array — expand to skills + mcp + scripts | | `mcp` | MCP server ids, array — connected in-loop | | `model` / `provider` | Model/provider override | | `effort` | `quick` \| `standard` \| `deep` — turn/parallel budget preset | | `python_executor` | `auto` \| `pyodide` \| `anthropic` \| `gemini` — run_python routing | | `instructions` | Extra instructions appended after skills | | `allowed_tools` | Tool fence, array — only these reach the LLM; omitted → fail-closed default fence | | `allowed_agents` | Agent fence for call_agent: array of ids, or `'all'` | | `denied_agents` | Array — subtracted from `allowed_agents: all` | | `success_criteria` | Array of self-checked statements | | `max_turns` | Loop turn cap, positive number (`max_iterations` is a legacy alias; optional — effort/agent default applies when absent) | | `max_parallel` | Widest fan-out one delegate call may spawn (cap-and-refuse) | | `max_tokens` | Per-turn OUTPUT token budget for the loop's model calls (runtime default 16384) | | `budget_usd_run` | Per-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 | | `permissions` | Map of tool → `allow` \| `ask` \| `deny` (`ask` pauses the run for human approval) | | `permission_locks` | Admin-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_owner` | Memory 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`. | | `local` | `true` = 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_agents` | Which 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. ```yaml - 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 string` | Add a top-level `name:` | | `Workflow must have at least one task` | Add 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' string` | Add `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 array` | Put the inner tasks under `subtasks:` | | `Type 'dynamic' requires a generator object with at least an 'agent' field` | Add `generator: { agent: ... }` | | `Type 'batch' requires either 'items' (array) or 'items_from' (task ID string)` | Provide the item source | | `Type 'debate' requires at least 2 debaters` | Add a second debater | | `Rounds must be a positive integer between 1 and 5` | Fix `rounds:` | | `Aggregation must be one of: consensus, majority, all_pass, any_pass` | Fix `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 integer` | Fix `max:` on the dynamic block | # Workflows — execute_workflow, get_workflow_status, list_workflows, workflow, build_workflow, executions Source: https://docs-preview.plungeai.com/skills/plungeai-workflows/references/mcp <!-- 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: <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. # Workflows — CNL orchestration: what it is and how to run it Source: https://docs-preview.plungeai.com/skills/plungeai-workflows/references/overview <!-- sources-of-truth: orchestration/cnl-engine/README.md, orchestration/cnl-engine/schema-types.ts, orchestration/api-gateway/openapi.ts, orchestration/mcp-gateway/server.ts, apps/ocean-skills/skills/plungeai-workflows/SKILL.md | last-synced: 2026-09-24 --> A **workflow** is a YAML document (CNL — Cognitive Natural Language) that the engine executes as a DAG of agent calls: parallel fan-out, sequential pipelines, unlimited nesting, conditions, batches, debates, and bounded autonomous missions. The engine is pure orchestration — it routes tasks to agents over RPC and coordinates data handoff; agents do the actual work. > **Authoring belongs to this `plungeai-workflows` skill** — full CNL spec, validation > rules, recipes, and runnable examples ([`references/cnl-spec.md`](/skills/plungeai-workflows/references/cnl-spec), `recipes.md`, > `examples/`). This reference is the platform-level view: what workflows can do, > the facts that shape good designs, and every way to execute one. Do not write > non-trivial YAML without the authoring skill loaded. ## Shape of a workflow ```yaml name: Research and synthesize tasks: - type: parallel id: research subtasks: - { type: task, id: web, agent: brave-agent, query: "{input}" } - { type: task, id: deep, agent: exa-agent, query: "{input}" } - type: task id: synthesize agent: llm-agent prompt: "Synthesize the research above into a brief on: {input}" ``` Data flows automatically: each task's result lands in SharedMemory and downstream tasks receive upstream content — you never hand-wire results. Ten task types exist: | Type | One line | |---|---| | `task` | Single agent call (the default) | | `parallel` | All `subtasks` dispatched at once | | `sequential` | `subtasks` in order, each seeing prior results | | `dynamic` | Generator agent produces N items → executors fan out over them | | `batch` | Per-item pipeline over a list — isolated; per-item tracking + resume is opt-in `track: true` | | `debate` | N debaters, up to 5 rounds, optional judge | | `validate` | Macro → parallel PASS/FAIL validators + judge verdict | | `output` | Deliver a previous result (email/document) with a format transform | | `harness` | Bounded autonomous mission — see `plungeai-missions` | | `agent_loop` | Legacy alias for `harness` — prefer `harness` | Blocks (`parallel`/`sequential`/`batch`/`dynamic`/`debate`/`validate`) never carry `agent:` themselves; agents go on inner tasks. Conditions (`condition:` CEL, e.g. `input.contains('urgent')` or `qa_gate.verdict == "FAIL"`) gate any task or block before dispatch. ## Parallelism — the facts that should shape your designs These are structural (read from engine code) and measured (from the engine's own server-side event timestamps): - `type: parallel` dispatches **every** subtask at once — one `Promise.all`, no chunking, no width cap. Each child is a **separate Worker invocation** over RPC. - Engine overhead is **zero at every width** measured (1 → 100 children): dispatch spread 0 ms; workflow total equals the slowest child to the millisecond. A parallel block costs *the slowest of N*, not N of anything. The same 12 search tasks: sequential 18.9 s, parallel 1.9 s. - **I/O-bound fan-out is flat** — children waiting on networks do not contend, even against the same agent service. - **CPU-bound or isolate-heavy children queue at the destination**, not in the engine. Practical width against ONE shared destination: **~12-50** depending on the service; past that you are queueing, not gaining. To go wider, spread children across distinct destinations (a real research fan-out across six search providers does this naturally). - Every child's result is durable in SharedMemory — collect at the end or pick up each as it lands. - Measure with an A/B (`sequential` vs `parallel` of the same tasks), never by dividing a parallel total by a single-task average. ## Inputs and placeholders `{input}` is the primary input; `{input1}`…`{input10}` and any custom `{semantic_name}` also work — declared under `inputs:` and replaced in one pass. **Date tokens** (for rolling windows — scheduled runs especially): `{now}`, `{today}`, `{yesterday}`, `{week_start}`, `{week_end}`, `{last_week_start}`, `{last_week_end}`, `{month_start}`, `{month_end}`, `{last_month_start}`, `{last_month_end}`. All UTC, ISO weeks (Monday first), seeded from the run's execution time; a caller-supplied input of the same name wins. See `plungeai-scheduling` for the pattern. **Search-query guard:** search agents cap query length (per their cards) and an over-limit query — typed or auto-filled from a prior task's output — returns a structured `needs_input` refusal; nothing is silently truncated. Give search tasks short explicit queries; bulk upstream data flows as context, never as the query. ## Executing a workflow ### MCP (preferred when operating live) ``` # Ad-hoc (test before saving — always) plungeai_execute_workflow {workflow_yaml: "<yaml>", input: "solid-state batteries"} # Long run plungeai_execute_workflow {workflow_yaml: "<yaml>", input: "…", mode: "async"} # → execution_id → plungeai_get_workflow_status → plungeai_get_result # Saved workflow by id plungeai_execute_workflow {workflow_id: "…", input: "…"} ``` YAML gotchas the platform will refuse: hard-wrapped values (use block scalars `prompt: |`), unquoted values containing colons, invented fields (`depends_on`, `outputs:`, `parallel: true`, `schedule:` — scheduling is a separate system, see `plungeai-scheduling`). Or skip hand-writing: `plungeai_build_workflow {goal}` generates and saves one via the platform builder. Manage saved workflows with `plungeai_workflow` (`action: create|get|update|delete|save_version|list_versions|get_version|restore_version`) — create/update/delete sync live to Studio and peer apps. Create/update also take `folder` (file/move it — `"none"` clears) and `kind: workflow|agent|bot` (which sidebar section it lives in: Flows, Agents, or Bot agents). This is the mechanic behind the "my agents" terminology: a saved item with `kind: agent` IS the user's "agent", and `plungeai_list_workflows` filters by `folder`. Server-side validation on save is your final gate: a refusal lists field errors; fix exactly those. Pre-built starting points: `plungeai_templates {action: list|get|use}`. ### One API ```bash # Inline (JSON wrapper or raw text/yaml body) curl -s -X POST https://api.plungeai.com/v1/workflows/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{"workflow": "name: quick\ntasks:\n - agent: brave-agent\n query: \"{input}\"\n", "input": "latest AI news"}' # → {success, workflow_id, final_task_id, request_id} # Saved workflow by id (resolved against your user) curl -s -X POST https://api.plungeai.com/v1/workflows/{id}/execute \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{"input": "latest AI news"}' # Live progress: SSE stream of engine events curl -N -X POST https://api.plungeai.com/v1/workflows/{id}/execute-stream \ -H "Authorization: Bearer ozk_YOUR_KEY" -H "Content-Type: application/json" \ -d '{"input": "…"}' ``` The acknowledgement is a pointer, not the content. Redeem results: ```bash curl -s https://api.plungeai.com/v1/workflows/results/{workflowId}/{taskId} \ -H "Authorization: Bearer ozk_YOUR_KEY" # 200 {content, content_type, workflow_id, task_id} | 404 not_ready (still running) ``` `final_task_id` from the acknowledgement is the task id of the final result; any intermediate task id works too (read one branch of a fan-out). Errors: `400 missing_workflow`, `404 workflow_not_found`, `502 engine_error`. ### Studio Humans edit and run workflows visually; the Code tab accepts pasted YAML with inline validation. Point users there for visual work and credential connects. ## Reading results - MCP: `plungeai_get_result {workflow_id}` → final output (full conversation thread for conversational runs); add `task_id` for a single step. Output is final user-ready markdown — relay verbatim. - One API: the `/results/` endpoints above. - Execution completed but "results not yet available" → retry `plungeai_get_result`; storage is eventually consistent by a beat. ## Follow-ups A completed execution can be continued conversationally: `plungeai_followup {execution_id, prompt: "<follow-up question>"}` — `prompt` is the required parameter (`message` belongs to `plungeai_continue`, the HITL resume tool — do not cross them). It reuses the run's context. Workflows may carry a `followup:` block (provider/model/memory_scope/temperature/max_tokens) which the engine ignores at execution time; it configures this follow-up behavior. Full conversation/HITL detail: `plungeai-results-traces`. ## Failure semantics worth knowing - Parallel branches are best-effort: a failed branch does not abort the run; the summary carries `failed_branches[]` (present only when something was lost). Check it before trusting a synthesis over fan-out results. - Per-task `retry: N` (max 2) exists for plain `type: task` only — never for `harness` — and re-fires the FULL agent call: set it only on read-only/idempotent agents, never payment/messaging/automation classes. - The execution summary (`total_tasks_executed`, `tasks_skipped`, `parallel_blocks_executed`, per-task durations) is your first debugging read — see `plungeai-results-traces`. # CNL recipes — pick the shape, then adapt Source: https://docs-preview.plungeai.com/skills/plungeai-workflows/references/recipes <!-- sources-of-truth: orchestration/cnl-engine/schema-types.ts, apps/ocean-skills/skills/plungeai-workflows/examples/ | last-synced: 2026-09-24 --> Full runnable versions live in `examples/`. Two composition rules apply to all of them: - **Wrap independent work in `parallel`** — the engine fans out ALL subtasks at once over RPC; width is nearly free for I/O-bound work. - **Prompt-chaining beats mega-prompts** — pass `{data:task_id}` forward through small focused tasks instead of one giant prompt. ## 1. Single task (`examples/01-simple-search.yaml`) The smallest valid workflow: one agent, one prompt. Use for smoke tests and one-shot calls. ```yaml tasks: - type: "task" id: "single_task" agent: brave-agent prompt: "{input}" ``` ## 2. Parallel research + synthesis (`examples/02-parallel-research.yaml`) **The most common production pattern.** Independent searches from different engines fan out at once; one LLM task synthesizes with `{data:...}` references. ```yaml tasks: - type: "parallel" id: "research_phase" subtasks: [ …brave-agent…, …tavily-agent…, …exa-agent… ] - type: "task" id: "synthesis" agent: llm-agent prompt: "Synthesize: {data:brave_search} {data:tavily_research} {data:exa_deep}" ``` ## 3. Hierarchical branches (`examples/03-hierarchical.yaml`) parallel → sequential → parallel nesting, unlimited depth. Use when branches have internal pipelines (e.g. search → per-branch analysis) that should still run side by side. ## 4. Consensus validation (`examples/04-validate-consensus.yaml`) Produce something, then have several validators vote (`aggregation: consensus | majority | all_pass | any_pass`). Use for quality gates on generated content. ```yaml - type: "validate" id: "quality_gate" validators: - { agent: llm-agent, validation_rule: "claims are sourced" } - { agent: llm-agent, validation_rule: "no speculation stated as fact" } aggregation: "majority" ``` ## 5. Per-item batch (`examples/05-batch-items.yaml`) Same pipeline for every item in a list (`items:` static or `items_from:` a prior task). `{item}` / `{item.field}` inside the pipeline; data chains automatically between the pipeline's tasks. Add `track: true` for resumable long lists. ## 6. Bounded harness mission (`examples/06-harness-mission.yaml`) Open-ended, goal-driven work = ONE `type: harness` task with a mission (purpose, effort, `max_turns`, `success_criteria`) — not ten hand-planned small tasks. The loop runtime plans, uses tools, and self-checks inside the fence you declare. Reach for it when the steps can't be enumerated up front. ## Choosing between `dynamic`, `batch`, and `harness` - Know the list already → `batch`. - An agent must generate the list first, then each item gets the same treatment → `dynamic` (`generator` + `executors`, cap with `max`). - The steps themselves are unknown and the agent must decide as it goes → `harness`. ## Debate (no example file — shape only) Two or more debaters argue positions, optional judge decides, `rounds: 1-5`. Use for decisions with genuine trade-offs. ```yaml - type: "debate" id: "build_vs_buy" debaters: - { agent: llm-agent, position: "build in-house" } - { agent: llm-agent, position: "buy off the shelf" } judge: { agent: llm-agent } rounds: 2 ``` # plungeai-in-bolt Source: https://docs-preview.plungeai.com/skills/plungeai-in-bolt Connect Bolt.new to PlungeAI (Ocean Studio) over MCP — the Connectors → Custom MCP server form, the all-tools/all-projects toggle behavior, keeping the shipped app's key server-side, and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in Bolt.new and says connect / install / set up PlungeAI, mentions Custom MCP server, or a deployed Bolt app 401s against PlungeAI. For another builder use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-bolt.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-bolt/SKILL.md) Bolt is a hosted builder: there is no local config file and no JSON entry anywhere — the connector form is the only surface, and the key lives only in its credential. ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Connect (once) From the Bolt homepage chatbox: click the **+** icon → **Connectors** → **Manage connectors** → **Custom MCP server**, then fill: | Field | Value | |---|---| | Name | `PlungeAI` | | URL | `https://mcp.plungeai.com/v1` | | Transport type | `HTTP` (use `SSE` only if a server's docs say so — PlungeAI's is HTTP) | | Authentication | select **API key** and enter the `ozk_` key (or **MCP OAuth** — not available for PlungeAI yet) | Bolt does not document which header the API-key field sends; the PlungeAI server accepts both `X-API-Key: ozk_YOUR_KEY` and `Authorization: Bearer ozk_YOUR_KEY`, so the raw key works — confirm with `plungeai_whoami` (Verify below). ## Verify 1. Builder chat: "use plungeai_whoami to confirm my identity" → an identity card. 2. Generated app (server side): `curl -H "Authorization: Bearer ozk_YOUR_KEY" https://api.plungeai.com/v1/agents` → HTTP 200 JSON. 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. ## Quirks — the toggles that bite - **Auto-enable for all projects** controls whether the connector turns on automatically in each new project — existing projects enable it from the same Connectors menu. - Adding a connector turns on all its tools by default, and the tool list is global — you can't turn tools on/off per project. Trim the tool list once, globally, if the builder gets tool-choice-noisy. - Tools missing mid-session → Manage connectors: check the connector is enabled for this project and its tool toggles are on, then retry. - The connector credential authenticates the BUILDER only. The shipped app needs its own wiring: a server function holding `PLUNGEAI_API_KEY` as an env var that proxies the One API. An app that "worked in preview" but 401s when deployed usually shipped without the env var set. The key must never appear in the client bundle or a browser `fetch`. - Long CNL workflows can exceed a builder-chat step budget — prefer async mode (`plungeai_execute_workflow` with `mode: "async"` + `plungeai_get_workflow_status`). ## Where next - Writing the server-side proxy that calls `https://api.plungeai.com`: **plungeai-api-setup**. - Operating the `plungeai_*` tools in chat: **plungeai-mcp-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-claude-ai Source: https://docs-preview.plungeai.com/skills/plungeai-in-claude-ai Connect claude.ai web or Claude Desktop to PlungeAI (Ocean Studio) — Desktop live tools via the mcp-remote bridge in claude_desktop_config.json (OAuth isn't available yet, hence the bridge), claude.ai web via skill.zip upload, and a plungeai_whoami + plungeai_list_agents verify for Desktop. Use when the user is on claude.ai or Claude Desktop and says connect / install / set up PlungeAI, mentions claude_desktop_config.json, Customize → Skills, or a PlungeAI tool call there is failing. For the Claude Code CLI use plungeai-in-claude-code; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-claude-ai.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-claude-ai/SKILL.md) Two different surfaces, two different capabilities: | Surface | What it gets | |---|---| | **Claude Desktop** | live `plungeai_*` MCP tools, via a bridge (below) | | **claude.ai (web)** | a PlungeAI *skill* upload — Claude produces paste-ready CNL workflows for Ocean Studio, not live tool calls (claude.ai has no custom-connector bearer-header field yet) | ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. - Desktop only: Node.js installed (the bridge runs via `npx`). ## Connect (once) — Claude Desktop **Why a bridge:** Settings → Connectors → Add custom connector authenticates through OAuth only (no bearer-header field), and PlungeAI OAuth hasn't shipped. Until it does, Desktop connects through the `mcp-remote` stdio bridge. Settings → Developer → **Edit Config** opens the file — macOS `~/Library/Application Support/Claude/claude_desktop_config.json`, Windows `%APPDATA%\Claude\claude_desktop_config.json`. Merge: { "mcpServers": { "plungeai": { "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.plungeai.com/v1", "--header", "Authorization: Bearer ozk_YOUR_KEY"] } } } Quit Claude Desktop completely and relaunch — the config is only read at start. ## Connect (once) — claude.ai web (skill only) Needs code execution enabled first: **Settings → Capabilities** → turn on **Code execution and file creation** (a prerequisite for any custom skill upload, not PlungeAI-specific). Then **Customize → Skills → + → Upload a skill** — upload https://mcp.plungeai.com/skill.zip. This teaches Claude PlungeAI conventions; it does not give claude.ai a live MCP connection. ## Verify (Claude Desktop) 1. Ask Claude: "use plungeai_whoami to confirm my identity" → an identity card (user id, auth tier, key label, rate window, server). 2. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. claude.ai web has no live tool call to verify — a successfully uploaded skill is the only signal; ask Claude to draft a PlungeAI CNL workflow to confirm it loaded. ## Quirks - **Windows:** Desktop does not escape spaces inside `args` — if the bridge 401s only on Windows, replace the header arg with `"--header", "Authorization:${AUTH_HEADER}"` plus `"env": { "AUTH_HEADER": "Bearer ozk_YOUR_KEY" }` in the same entry. - Logs: `~/Library/Logs/Claude/mcp*.log` (macOS) · `%APPDATA%\Claude\logs` (Windows) — check these before re-editing the config. - The bridge is an `npx` process — a cold start can take a few seconds; if tools "never appear," wait, then check the logs above. - Long CNL workflow runs: prefer `mode: "async"` + `plungeai_get_workflow_status` polling — Desktop caps a single synchronous tool call. - Money-verb operations (payments, sends) still stop: a gated call pauses with a structured `needs_approval` outcome — relay it to the user, then `plungeai_continue`; never retry blind. - 401 through the bridge but the key looks right → whitespace or a missing `ozk_` prefix; re-paste it into the config. ## Where next - The Claude Code CLI instead of Desktop/web: **plungeai-in-claude-code**. - Operating the `plungeai_*` tools once connected: **plungeai-mcp-setup**. - Writing code that calls `https://api.plungeai.com` directly: **plungeai-api-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-claude-code Source: https://docs-preview.plungeai.com/skills/plungeai-in-claude-code Connect the Claude Code CLI to PlungeAI (Ocean Studio) over MCP — 'claude mcp add' one-liner, project-scoped .mcp.json with an env-var key, the skills/plugin install path, and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in Claude Code and says connect / install / set up PlungeAI, add an MCP server, mentions claude mcp add or ozk_, or a PlungeAI tool call in Claude Code is failing. For claude.ai web or Claude Desktop use plungeai-in-claude-ai; for another editor use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-claude-code.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-claude-code/SKILL.md) Claude Code talks to PlungeAI over the Streamable HTTP MCP server at `https://mcp.plungeai.com/v1`. One `ozk_` bearer key authenticates it (and the One API, if generated code calls PlungeAI directly). ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. - Claude Code CLI installed and on PATH (`claude --version`). ## Connect (once) ### Terminal one-liner (simplest) claude mcp add --transport http plungeai https://mcp.plungeai.com/v1 \ --header "Authorization: Bearer ozk_YOUR_KEY" --scope user - Default scope is `local` — this project only, stored in `~/.claude.json`. `--scope user` makes the server available in every project (same file). - **Never `--scope project` with a literal key** — that writes the key into `.mcp.json` inside the repo, which gets committed. ### Project-scoped `.mcp.json` (committed-safe, env-var key) Use this when the team should share the server definition in the repo without anyone's literal key landing in git: { "mcpServers": { "plungeai": { "type": "http", "url": "https://mcp.plungeai.com/v1", "headers": { "Authorization": "Bearer ${PLUNGEAI_API_KEY}" } } } } Export `PLUNGEAI_API_KEY` in each developer's own shell before launching Claude Code — the file itself never holds a literal key, so it's safe to commit. ## Verify 1. `claude mcp list` (or `/mcp` inside a session) shows `plungeai` connected. 2. Ask Claude: "use plungeai_whoami to confirm my identity" → an identity card (user id, auth tier, key label, rate window, server). 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog — proves the catalog is reachable, not just auth. ## Quirks - `tools/list` is authoritative: a key can be fenced to a subset of `plungeai_*` tools — seeing fewer tools than a colleague is policy, not a bug. - Money-verb operations (payments, sends) still stop: a gated call pauses with a structured `needs_approval` outcome (relay it, then `plungeai_continue` once the user decides) regardless of any auto-approve setting — never retry blind, never approve on your own. - Long CNL workflow runs: prefer `mode: "async"` + `plungeai_get_workflow_status` polling over one long synchronous call. - Skills for the agent — teach PlungeAI conventions (discovery-first, CNL authoring) as an installable skill directory: - **Public repo `PlungeAI/plungeai-agent-skills` — once published**: `npx skills add PlungeAI/plungeai-agent-skills` (installs into `.agents/skills/` or `.claude/skills/`, `-g` for the user-level home `~/.claude/skills/`), or `claude plugin marketplace add PlungeAI/plungeai-agent-skills` then `claude plugin install plungeai@plungeai`. - **Working today:** download https://mcp.plungeai.com/skill.zip and unzip into `.claude/skills/` (or `~/.claude/skills/`). - 401 (`Invalid API key`, or `No valid authentication provided...` if the header itself is missing) → key typo'd, pasted with whitespace, or the header never made it into `~/.claude.json` / `.mcp.json` — re-check the header field, not the key value. - Connected but no `plungeai_*` tools listed → restart the session after any config edit before debugging further. ## Where next - Operating the `plungeai_*` tools once connected: **plungeai-mcp-setup**. - Writing code that calls `https://api.plungeai.com` directly: **plungeai-api-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - CNL workflow YAML authoring: **plungeai-workflows**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-codex Source: https://docs-preview.plungeai.com/skills/plungeai-in-codex Connect OpenAI Codex CLI to PlungeAI (Ocean Studio) over MCP — native streamable-HTTP in ~/.codex/config.toml (env-var or static bearer token), the codex mcp add terminal command, the mcp-remote bridge fallback, and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in Codex CLI (or asks about ChatGPT + PlungeAI) and says connect / install / set up PlungeAI, mentions config.toml or mcp_servers, or plungeai_* tools never appear. ChatGPT web has no PlungeAI connector yet (OAuth pending) — Codex CLI is the OpenAI-ecosystem door. For another editor use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-codex.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-codex/SKILL.md) Codex CLI talks to PlungeAI over the Streamable HTTP MCP server at `https://mcp.plungeai.com/v1`. One `ozk_` bearer key authenticates it (and the One API, if generated code calls PlungeAI directly). This is also the OpenAI-ecosystem door today: ChatGPT web connectors require OAuth (PlungeAI OAuth in progress), so ChatGPT users connect through Codex CLI instead. ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Connect (once) — native streamable HTTP (primary) Codex supports remote streamable-HTTP servers natively. In `~/.codex/config.toml` (user-level TOML — the right home for anything key-related): [mcp_servers.plungeai] url = "https://mcp.plungeai.com/v1" bearer_token_env_var = "PLUNGEAI_API_KEY" Export `PLUNGEAI_API_KEY` in the shell profile; the config file itself never holds the key, so this pattern is safe even if the file is shared. A static header works too — user-level file only, never committed: http_headers = { Authorization = "Bearer ozk_YOUR_KEY" } Or from the terminal: codex mcp add plungeai --url https://mcp.plungeai.com/v1 --bearer-token-env-var PLUNGEAI_API_KEY codex mcp list ## Fallback — mcp-remote bridge (only if the build lacks native `url`) [mcp_servers.plungeai] command = "npx" args = ["-y", "mcp-remote", "https://mcp.plungeai.com/v1", "--header", "Authorization: Bearer ozk_YOUR_KEY"] startup_timeout_sec = 30 `startup_timeout_sec` defaults to **10 s** — an npx cold start can exceed it, and then the tools "never appear" with no useful error; set 30. If the bridge 401s, the client is mangling spaces inside `args` — switch to the native form above rather than fighting the quoting. ## Verify 1. `codex mcp list` shows `plungeai` (or `/mcp` in the TUI shows it connected). 2. Ask Codex: "use plungeai_whoami to confirm my identity" → an identity card. 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. ## Quirks - `config.toml` is TOML, not JSON — no braces or trailing commas; the table header is exactly `[mcp_servers.plungeai]` (underscore, not dash). - `tool_timeout_sec` defaults to 60 s — long CNL workflows should run in async mode (`plungeai_execute_workflow` with `mode: "async"` + `plungeai_get_workflow_status`) rather than one long synchronous call. - `/mcp` inside the Codex TUI shows active MCP servers and their status; `codex mcp get plungeai` / `codex mcp remove plungeai` manage the entry. - Codex approval modes gate tool calls; in full-auto the money-verb PlungeAI operations still pause with a structured `needs_approval` outcome — relay it, then `plungeai_continue`. - `enabled = false` disables the server without deleting the entry. - ChatGPT web: no PlungeAI connector yet — OAuth is in progress. Point ChatGPT users at Codex CLI in the meantime. ## Where next - Operating the `plungeai_*` tools once connected: **plungeai-mcp-setup**. - Writing code that calls `https://api.plungeai.com` directly: **plungeai-api-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-cursor Source: https://docs-preview.plungeai.com/skills/plungeai-in-cursor Connect Cursor to PlungeAI (Ocean Studio) over MCP — the one-click install-page deeplink or a ~/.cursor/mcp.json entry, Agent/Plan-mode tool behavior, the ~40-tool cap, and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in Cursor and says connect / install / set up PlungeAI, mentions mcp.json or the install page, asks whether PlungeAI works in Cursor, or plungeai_* tools aren't showing up. For another editor use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-cursor.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-cursor/SKILL.md) Cursor talks to PlungeAI over the Streamable HTTP MCP server at `https://mcp.plungeai.com/v1`. One `ozk_` bearer key authenticates it (and the One API, if generated code calls PlungeAI directly). ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Connect (once) ### One click 1. Open https://mcp.plungeai.com/install, **type the `ozk_` key into the box at the top**, then click **Add to Cursor**. Cursor prompts to install the server — confirm. 2. Cursor never asks for a header: clicked without the key, the server installs auth-less (401, red status) and the `headers` block must be added by hand afterwards (below). ### By hand Merge into `~/.cursor/mcp.json` (user-level — the right home for the key): { "mcpServers": { "plungeai": { "url": "https://mcp.plungeai.com/v1", "headers": { "Authorization": "Bearer ozk_YOUR_KEY" } } } } A project-scoped `.cursor/mcp.json` gets committed — there, reference an env var instead: `"Authorization": "Bearer ${env:PLUNGEAI_API_KEY}"` (Cursor interpolates `${env:…}` in `command`, `args`, `env`, `url`, and `headers`). ## Verify 1. Settings → MCP → `plungeai` shows a green dot with tools listed. 2. In Agent chat: "use plungeai_whoami to confirm my identity" → an identity card. 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. ## Quirks - MCP tools fire in **Agent** and **Plan** modes; **Ask** mode is read-only and won't call them. - Tool calls run behind per-call approval by default. Money-verb PlungeAI operations still pause with a structured `needs_approval` outcome even under auto-run — relay it, then `plungeai_continue`. - Tool cap: users report a limit of roughly 40 MCP tools sent to the model across all servers (unverified, not in Cursor's current docs). If `plungeai_*` tools are missing, disable unused servers or toggle off unneeded tools, then reopen the chat. - After editing `mcp.json`, toggle the server off/on in Settings → MCP (or restart Cursor) before debugging anything else. - Red status / "No tools found" right after install → check auth first: the `headers` object must sit *inside* the `plungeai` entry (not beside it) and the key must be intact. - Keep future sessions discovery-first with a one-liner in `.cursor/rules/plungeai.mdc`: "PlungeAI: agent ids come from a live `plungeai_list_agents` search — never from memory." Rules files are committed — never put the key there. ## Where next - Operating the `plungeai_*` tools once connected: **plungeai-mcp-setup**. - Writing code that calls `https://api.plungeai.com` directly: **plungeai-api-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-gemini-cli Source: https://docs-preview.plungeai.com/skills/plungeai-in-gemini-cli Connect Gemini CLI to PlungeAI (Ocean Studio) over MCP — a ~/.gemini/settings.json entry using httpUrl (not url, which is SSE-only and 405s), the mcp-remote bridge fallback, /mcp reload after edits, and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in Gemini CLI and says connect / install / set up PlungeAI, mentions settings.json or httpUrl, or plungeai_* tools come up empty. For another editor use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-gemini-cli.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-gemini-cli/SKILL.md) Gemini CLI talks to PlungeAI over the Streamable HTTP MCP server at `https://mcp.plungeai.com/v1`. One `ozk_` bearer key authenticates it (and the One API, if generated code calls PlungeAI directly). ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Connect (once) Merge into `~/.gemini/settings.json` (user-level — the right home for the key): { "mcpServers": { "plungeai": { "httpUrl": "https://mcp.plungeai.com/v1", "headers": { "Authorization": "Bearer ozk_YOUR_KEY" } } } } **The key name is `httpUrl`** — Gemini CLI reserves `url` for SSE servers, and the PlungeAI endpoint rejects SSE-style GETs with an immediate 405, so a `url` entry fails to connect. This is the #1 misconfiguration on this tool. If the build lacks `httpUrl`, bridge with mcp-remote instead: { "mcpServers": { "plungeai": { "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.plungeai.com/v1", "--header", "Authorization: Bearer ozk_YOUR_KEY"] } } } A project-scoped `.gemini/settings.json` gets committed — keep the literal key in the user-level file only. ## Verify 1. `/mcp` inside the CLI lists `plungeai` with its tools. 2. Ask Gemini: "use plungeai_whoami to confirm my identity" → an identity card. 3. Transport-independent check: `curl -H "Authorization: Bearer ozk_YOUR_KEY" https://api.plungeai.com/v1/agents` → HTTP 200 JSON. Then "use plungeai_list_agents to search 'web search'" from inside the CLI → live results from the active agent catalog. ## Quirks - `/mcp reload` re-connects all MCP servers and re-discovers tools after a settings edit — `/mcp refresh` exists on some builds but has had reload bugs upstream; if either doesn't pick up the change, restart the CLI. - Per-tool confirmation is the default; `"trust": true` on the server entry skips it. Money-verb PlungeAI operations still pause with a structured `needs_approval` outcome regardless — relay it, then `plungeai_continue`. - A previously working setup whose tool list comes up empty usually means the key was revoked/expired (the handshake now 401s) — re-check with the curl line above before touching the config. - A `GEMINI.md` line with a discovery-first reminder ("PlungeAI agent ids come from a live `plungeai_list_agents` search — never from memory") keeps every session honest. Context files are committed — never put the key there. ## Where next - Operating the `plungeai_*` tools once connected: **plungeai-mcp-setup**. - Writing code that calls `https://api.plungeai.com` directly: **plungeai-api-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-lovable Source: https://docs-preview.plungeai.com/skills/plungeai-in-lovable Connect Lovable to PlungeAI (Ocean Studio) — a personal chat connector (any plan) so Lovable's chat can operate PlungeAI via MCP while building, and a workspace-admin app connector so shipped apps call the One API in production with attached auth, plus a plungeai_whoami + plungeai_list_agents verify. Use when the user is in Lovable and says connect / install / set up PlungeAI, mentions Connectors or Custom MCP, or a Lovable-built app can't reach PlungeAI. For another builder use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-lovable.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-lovable/SKILL.md) Two connectors, two purposes: a **chat connector** (any plan) so Lovable's chat can operate PlungeAI while building, and an **app connector** (workspace admin) so the apps users ship call the One API in production. ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Path A — chat connector (any plan, 2 minutes) **Connectors → + → MCP server**: Server name `PlungeAI`, Server URL `https://mcp.plungeai.com/v1`, Authentication → bearer token / API key → paste the `ozk_` key. Lovable's chat now has the `plungeai_*` tools while building. - Chat connectors are **personal**: others in the workspace connect the same server themselves, each with their own key. - They are **build-time only** — never part of the published app. That is exactly why Path B exists. - Workspace admins can switch custom MCP servers off for everyone: **Connectors → Admin settings → Chat connectors → "Custom MCP"**. A non-admin who can't find "MCP server" in the picker is hitting this toggle. ## Path B — app connector (workspace admin) Creates a reusable custom connector: workspace members connect it to their apps, each pasting their own key; Lovable then attaches auth to every One API call the generated app makes. ### 1. Create the connector (Connectors → + → Custom connector) | Form field | Value | | --- | --- | | Display name | PlungeAI | | Category | Development | | Documentation URL | https://api.plungeai.com/docs | ### 2. Authentication | Field | Value | | --- | --- | | Authentication method | Bearer token | | API base URL | https://api.plungeai.com | | Test request → Method | GET | | Test request → Path | /v1/agents | Users paste their own `ozk_` key when they connect an app; Lovable verifies it against the verification path (green check = valid key). ### 3. Agent knowledge (attach to the connector) Give the connector these facts so generated code never adds its own Authorization header (the connector's auth layer already attaches it): - `GET /v1/agents` lists runnable agents (also the credential-verification path); `POST /v1/agents/{id}/execute` runs one, body `{ "input": "...", "sync": true }`, returning `{ "content": "...", "workflow_id": "...", "task_id": "...", "request_id": "..." }`. With `"sync": false` it returns 202 with the same pointer fields — redeem via `GET /v1/agents/results/{workflowId}/{taskId}`. - `GET /v1/discovery/search?q=...` finds the right agent by capability — always resolve ids this way, never guess. - `POST /v1/workflows/execute` runs CNL YAML/JSON; `GET /v1/workflows/results/{workflowId}/{taskId}` fetches the deliverable. - 403 `refused` / 409 `approval_required` are trust fences on money-verb tools — surface to the user, never retry. ## Verify 1. Chat: "use plungeai_whoami to confirm my identity" → an identity card. 2. App connector: connecting an app runs Lovable's verification (`GET /v1/agents`) → green check. 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. ## Quirks - Two different auth surfaces: the chat connector's key powers the BUILDER; each app's key is pasted by its owner when connecting the app connector. Never hardcode any key in the app itself. - If generated code contains an `Authorization` header, the knowledge wasn't attached to the connector, or the connector step was skipped — re-check step 3; the connector's own auth layer is the only place credentials belong. - The app connector is workspace-admin gated; non-admins use Path A for building and hand the admin this file for Path B. ## Where next - Route-by-route API manual (agents, tools, workflows, discovery, traces): **plungeai-api-setup**. - Operating the `plungeai_*` tools in chat: **plungeai-mcp-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-opencode Source: https://docs-preview.plungeai.com/skills/plungeai-in-opencode Connect OpenCode to PlungeAI (Ocean Studio) over MCP — an opencode.json mcp.plungeai entry with type: remote, {env:VAR} variable substitution for a committed project config, and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in OpenCode and says connect / install / set up PlungeAI, mentions opencode.json or the mcp key, or plungeai_* tools aren't responding. For another editor use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-opencode.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-opencode/SKILL.md) OpenCode talks to PlungeAI over the Streamable HTTP MCP server at `https://mcp.plungeai.com/v1`. One `ozk_` bearer key authenticates it (and the One API, if generated code calls PlungeAI directly). ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Connect (once) Merge into `~/.config/opencode/opencode.json` (user-level — the right home for the literal key) or the project's `opencode.json`: { "mcp": { "plungeai": { "type": "remote", "url": "https://mcp.plungeai.com/v1", "headers": { "Authorization": "Bearer ozk_YOUR_KEY" } } } } Note the shape: the top-level key is `mcp` (not `mcpServers`), and remote servers need `"type": "remote"`. For a committed project `opencode.json`, use OpenCode's variable substitution so the literal key never lands in the repo: "headers": { "Authorization": "Bearer {env:PLUNGEAI_API_KEY}" } (`{file:path}` substitution also exists for key files.) ## Verify 1. Ask OpenCode: "use plungeai_whoami to confirm my identity" → an identity card. 2. Transport-independent check: `curl -H "Authorization: Bearer ozk_YOUR_KEY" https://api.plungeai.com/v1/agents` → HTTP 200 JSON. 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. ## Quirks - Project config merges over the user config — if tools behave oddly, check whether a committed `opencode.json` (or `.jsonc`) redefines `mcp.plungeai`, e.g. with `"enabled": false`. - `{env:VAR}` resolves at startup: export `PLUNGEAI_API_KEY` before launching OpenCode, or the header goes out empty → 401. - MCP servers connect at startup — restart the OpenCode session after any config edit before debugging further. - OpenCode reads `AGENTS.md` — a discovery-first reminder ("PlungeAI agent ids come from a live `plungeai_list_agents` search — never from memory") belongs there. It is committed — never put the key in it. - Money-verb PlungeAI operations still pause with a structured `needs_approval` outcome (relay it, then `plungeai_continue`) regardless of any approval setting. ## Where next - Operating the `plungeai_*` tools once connected: **plungeai-mcp-setup**. - Writing code that calls `https://api.plungeai.com` directly: **plungeai-api-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-replit Source: https://docs-preview.plungeai.com/skills/plungeai-in-replit Connect Replit Agent to PlungeAI (Ocean Studio) over MCP — the one-click install-page link, the Integrations → MCP Servers form, keeping the Agent's MCP key separate from a deployed app's Replit Secret, and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in Replit and says connect / install / set up PlungeAI, mentions MCP Servers or Replit Secrets, or an app built in Replit 401s against PlungeAI. For another editor use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-replit.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-replit/SKILL.md) Replit talks to PlungeAI over the Streamable HTTP MCP server at `https://mcp.plungeai.com/v1` — for the Agent while building. Apps the Agent ships call the One API (`https://api.plungeai.com`) directly with their own key in Replit Secrets. ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Connect (once) ### One click 1. Open https://mcp.plungeai.com/install, **type the `ozk_` key into the box at the top**, then click **Add to Replit** — the integration imports with its Authorization header. Clicked without the key, add the header afterwards under the integration's **Advanced settings**. ### By hand Integrations → **MCP Servers** → **+ Add MCP server**: **Display name** `PlungeAI`, **Server URL** `https://mcp.plungeai.com/v1`, then **Advanced settings** → custom header `Authorization` = `Bearer ozk_YOUR_KEY`. The integration is account-level: the Agent gets the `plungeai_*` tools across all your projects, not just the current Repl. ## Verify 1. Ask the Agent: "use plungeai_whoami to confirm my identity" → an identity card. 2. From the Repl shell: `curl -H "Authorization: Bearer $PLUNGEAI_API_KEY" https://api.plungeai.com/v1/agents` → HTTP 200 JSON (proves a Repl Secret is set and valid). 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. ## Quirks - Two key locations — never mixed: the MCP integration's header (for the Agent) and **Replit Secrets** as `PLUNGEAI_API_KEY` (for the Repl's own code). Never in source files, `.replit`, or `replit.nix`. - A workspace app that 401s after deploy → check that the deployment's secrets carry `PLUNGEAI_API_KEY` too. - Tool approval: a tool that requires confirmation prompts before it runs. Money-verb PlungeAI operations still pause with a structured `needs_approval` outcome regardless — relay it, then `plungeai_continue`. - Standard split when the Agent is asked to "build an app that uses PlungeAI": it uses MCP to discover and test the right agent, then writes app code that calls the One API with the key from Replit Secrets. ## Where next - Operating the `plungeai_*` tools once connected: **plungeai-mcp-setup**. - Writing app code that calls `https://api.plungeai.com` directly: **plungeai-api-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-v0 Source: https://docs-preview.plungeai.com/skills/plungeai-in-v0 Connect v0 (Vercel) to PlungeAI (Ocean Studio) over MCP — the + menu → MCPs form, why the generated Next.js app must call PlungeAI through a server Route Handler (v0 apps can't call MCP directly), and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in v0 and says connect / install / set up PlungeAI, mentions the MCPs panel, or a generated v0 app 401s against PlungeAI. For another builder use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-v0.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-v0/SKILL.md) v0 is a hosted builder: no local config file and no JSON entry anywhere — the MCP form is the only surface, and the key lives only in that entry. ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Connect (once) Open the **+** menu in the prompt form → **MCPs** → add your own server (the project settings page offers the same via **Add MCP**): | Field | Value | |---|---| | Name | `PlungeAI` | | URL | `https://mcp.plungeai.com/v1` | | Authentication | **Bearer Token** → paste the `ozk_` key itself (v0 adds the `Bearer` prefix); or **Custom Headers** → `Authorization` = `Bearer ozk_YOUR_KEY`. If one form 401s, try the other. (`No Auth` and `OAuth` don't apply — PlungeAI OAuth hasn't shipped.) | Then pick the server's **permission mode**: **Disabled**, **Ask for Approval (Manual)**, or **Always Run (Auto)**. Manual is the sane default; money-verb PlungeAI operations still pause with a structured `needs_approval` outcome even under Auto — relay it, then `plungeai_continue`. ## The generated app cannot call MCP v0's generated code cannot use the MCP tools directly — pair the MCP with **Environment Variables**. So the split is: the builder chat operates PlungeAI over MCP; the generated Next.js app calls the One API server-side only, e.g. a Route Handler: // app/api/plungeai/route.ts export async function POST(req: Request) { const { input, agentId } = await req.json() const r = await fetch( `https://api.plungeai.com/v1/agents/${agentId}/execute`, { method: "POST", headers: { Authorization: `Bearer ${process.env.PLUNGEAI_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ input, sync: true }), }, ) return Response.json(await r.json()) } Key in a Vercel env var (`PLUNGEAI_API_KEY`, every environment that needs it), never in client components, never prefixed `NEXT_PUBLIC_`. ## Verify 1. Builder chat: "use plungeai_whoami to confirm my identity" → an identity card. 2. Generated app (server side): `curl -H "Authorization: Bearer ozk_YOUR_KEY" https://api.plungeai.com/v1/agents` → HTTP 200 JSON. 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. ## Quirks - v0 previews run without the project's env vars until linked/deployed — a preview 401 from the app does not mean the integration is wrong; verify with the curl check above, then set the env var on the Vercel project. - If generation puts the fetch in a `"use client"` component, regenerate with: "PlungeAI calls go through a Route Handler; the key stays server-side." - Long CNL workflows: prefer async mode (`plungeai_execute_workflow` with `mode: "async"` + `plungeai_get_workflow_status`) over one long synchronous builder-chat call. ## Where next - Writing the Route Handler / server code that calls `https://api.plungeai.com`: **plungeai-api-setup**. - Operating the `plungeai_*` tools in chat: **plungeai-mcp-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-vscode Source: https://docs-preview.plungeai.com/skills/plungeai-in-vscode Connect VS Code (GitHub Copilot agent mode) to PlungeAI (Ocean Studio) over MCP — the code --add-mcp CLI command, a committed-safe .vscode/mcp.json with an input-prompted key, the 128-tools-per-request cap, and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in VS Code/Copilot and says connect / install / set up PlungeAI, mentions mcp.json or code --add-mcp, or plungeai_* tools aren't appearing in agent mode. For another editor use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-vscode.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-vscode/SKILL.md) VS Code talks to PlungeAI over the Streamable HTTP MCP server at `https://mcp.plungeai.com/v1`. One `ozk_` bearer key authenticates it (and the One API, if generated code calls PlungeAI directly). ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Connect (once) ### From a terminal (simplest working path) code --add-mcp '{"name":"plungeai","type":"http","url":"https://mcp.plungeai.com/v1","headers":{"Authorization":"Bearer ozk_YOUR_KEY"}}' (PowerShell/cmd: double-quote the JSON and escape inner quotes with `\"`.) ### By hand — the committed-safe pattern `.vscode/mcp.json` in the workspace. The `inputs` block makes VS Code prompt for the key once and store it encrypted — the file never holds the key, so it is safe to commit: { "inputs": [ { "id": "plungeai-key", "type": "promptString", "password": true, "description": "PlungeAI ozk_ key" } ], "servers": { "plungeai": { "type": "http", "url": "https://mcp.plungeai.com/v1", "headers": { "Authorization": "Bearer ${input:plungeai-key}" } } } } Machine-wide instead: **MCP: Open User Configuration** (the `mcp.json` in your user profile), or **MCP: Add Server** → choose the user scope — same fields, outside any repo. The install page's "Add to VS Code" button emits one URL-encoded JSON object (`vscode:mcp/install?{"name":"plungeai","type":"http","url":…}`) — matching VS Code's documented deeplink shape. If it ever fails to parse, `code --add-mcp` or the file above works unconditionally. ## Verify 1. **MCP: List Servers** shows `plungeai` running; the Tools picker lists `plungeai_*`. 2. In Copilot agent chat: "use plungeai_whoami to confirm my identity" → an identity card. 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. ## Quirks - MCP tools run in **agent mode** (Chat view → mode picker → Agent). The `plungeai_*` tools appear in the chat Tools picker once the server starts. - **128 tools max per chat request**, across all sources. Over the limit: deselect other servers/tools in the Tools picker, or rely on virtual tools — `github.copilot.chat.virtualTools.threshold` auto-groups tools beyond the threshold and lets the model expand a group on demand. - Mistyped key: **MCP: List Servers** → `plungeai` → **Show Output** shows the 401. Restart the server from the same menu; if it doesn't re-prompt for the stored input, remove and re-add the server. - Locked-down setups: `chat.mcp.access` governs which MCP servers can be used; org policies (`ChatAllowedMcpServers` / `ChatDeniedMcpServers` / `ChatAllowManagedMcpServersOnly`) allow- or deny-list servers — a missing MCP section in settings usually means one of these. - Trust: VS Code asks you to confirm you trust the server before first start — except when it's started directly from `mcp.json`. - Money-verb PlungeAI operations still pause with a structured `needs_approval` outcome (relay it, then `plungeai_continue`) regardless of any trust/confirmation setting. ## Where next - Operating the `plungeai_*` tools once connected: **plungeai-mcp-setup**. - Writing code that calls `https://api.plungeai.com` directly: **plungeai-api-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-in-windsurf Source: https://docs-preview.plungeai.com/skills/plungeai-in-windsurf Connect Windsurf (Cascade) to PlungeAI (Ocean Studio) over MCP — a ~/.codeium/windsurf/mcp_config.json entry using serverUrl, the mcp-remote bridge fallback for stdio-only builds, the 100-tool cap, and a plungeai_whoami + plungeai_list_agents verify. Use when the user is in Windsurf/Cascade and says connect / install / set up PlungeAI, mentions mcp_config.json or serverUrl, or plungeai_* tools aren't showing up. For another editor use its plungeai-in-<tool> skill; for an unlisted but MCP-capable client use plungeai-mcp-setup's generic client config. [Download zip](https://skills.plungeai.com/plungeai-in-windsurf.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-in-windsurf/SKILL.md) Windsurf talks to PlungeAI over the Streamable HTTP MCP server at `https://mcp.plungeai.com/v1`. One `ozk_` bearer key authenticates it (and the One API, if generated code calls PlungeAI directly). No install-page deeplink exists for Windsurf — it is a config-file tool. ## Prerequisites - An `ozk_` key: Dashboard → **One API → Keys** (https://dashboard.plungeai.com) — self-service, shown once, copy it now. ## Connect (once) Merge into `~/.codeium/windsurf/mcp_config.json` (user-level — the right home for the key), then reload the MCP servers from Cascade's MCP panel or restart Windsurf: { "mcpServers": { "plungeai": { "serverUrl": "https://mcp.plungeai.com/v1", "headers": { "Authorization": "Bearer ozk_YOUR_KEY" } } } } `serverUrl` is the documented key for remote servers (the vendor docs also accept `url`; every vendor example uses `serverUrl` — stick with it). Older, stdio-only builds bridge with mcp-remote instead: { "mcpServers": { "plungeai": { "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.plungeai.com/v1", "--header", "Authorization: Bearer ozk_YOUR_KEY"] } } } ## Verify 1. Cascade's MCP panel shows `plungeai` with tools after a refresh. 2. In Cascade: "use plungeai_whoami to confirm my identity" → an identity card. 3. "use plungeai_list_agents to search 'web search'" → live results from the active agent catalog. ## Quirks - Config edits are not hot-reloaded — refresh/reload the MCP panel (or restart Windsurf) after every change, before debugging anything else. - Tool cap: Cascade has a limit of roughly 100 total tools across all servers. If `plungeai_*` tools are missing, disable unused servers and refresh. - Discovery-first rules live in project `.windsurf/rules/*.md` (the legacy single-file `.windsurfrules` is also still read) or the global `~/.codeium/windsurf/memories/global_rules.md`. Rules files are committed — never put the key there. - Money-verb PlungeAI operations still pause with a structured `needs_approval` outcome (relay it, then `plungeai_continue`) regardless of any auto-run setting. ## Where next - Operating the `plungeai_*` tools once connected: **plungeai-mcp-setup**. - Writing code that calls `https://api.plungeai.com` directly: **plungeai-api-setup**. - Picking MCP vs the One API for a given job: **choose-your-plungeai-door**. - An unlisted but MCP-capable client, or the shared connect concepts (native remote vs. stdio bridge, key hygiene): **plungeai-mcp-setup**. - Full guide: https://mcp.plungeai.com/docs#3-connecting-clients # plungeai-agentic-agent Source: https://docs-preview.plungeai.com/skills/plungeai-agentic-agent Design and emit ONE bounded agentic agent for PlungeAI (Ocean Studio) as a single `type: harness` mission — purpose, allowed_tools fence, permissions gates (deny/ask), skills/plugins/MCP/persona declarations, effort or turn cap, success criteria — then hand it to Studio as CNL YAML. Use when the Studio Think composer has "Agentic agent" selected, or when a user asks to build/create an agentic agent, a mission agent, a bounded autonomous agent, or "an agent that can decide its own steps". Triggers: "agentic agent", "build an agent", "mission", "harness", "allowed tools", "what may it do". NOT for multi-task pipelines (plungeai-workflows) or scheduled reporting bots (plungeai-bot-agent). [Download zip](https://skills.plungeai.com/plungeai-agentic-agent.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-agentic-agent/SKILL.md) <Note> Used by Studio: Ocean Studio's agent builder loads this skill by its id. </Note> You are building ONE agent that decides its own steps inside hard bounds. The deliverable is exactly one `type: harness` task inside a `workflow:` wrapper. Studio validates it, lints it (one harness task, fence includes `task_complete`, no `memory_owner`) and saves it under the "Agentic agents" section. The user then runs it from Build → Run or talks to it turn by turn. ## The conversation (before any YAML) 1. **Purpose.** Restate the standing purpose in one sentence. If the goal is fuzzy, ask ONE question that splits the space ("verify claims" vs "write the brief"?). 2. **Boundaries — the fence.** Propose the smallest `allowed_tools` set that can achieve the purpose and say why each tool is in. Ask which of these the user wants gated (`permissions: {tool: ask}`) or removed. Never widen silently. 3. **Capabilities.** Only from the AVAILABLE CAPABILITIES index in your context (skills, plugins, mcp) and from live `registry_search` results (agents). Name the ids you intend to declare and what each adds. If none fit, declare none — an invented id degrades to a silent warning at run time. 4. **Human gates.** Anything that sends, pays, posts, deletes, or writes outside the workspace gets `ask` or is excluded. Payment-class agents are deny-unless-named. 5. **Budget.** `effort: quick | standard | deep` (4 / 12 / 20 turns) or an explicit `max_turns` (≤ 30). Default `standard`. 6. **Done means.** 2–4 `success_criteria` the agent checks before it finishes. Confirm the design in one short block, then emit the YAML. Ask, don't guess. ## Output contract Exactly ONE fenced `yaml` block, `workflow:` wrapper, ONE task. Nothing else in the block. ```yaml workflow: name: "<short agent name>" description: "<one line: what it does and for whom>" tasks: - type: harness id: agent goal: "{input}" mission: | You are <name>, <role>. <standing purpose in 2–4 sentences>. <house rules: sources, tone, refusals>. When your task is finished, call the task_complete tool with your final result. effort: standard allowed_tools: [web_search, web_fetch, load_skill, ask_user, task_complete] permissions: { call_agent: ask } skills: [<ids from the index>] plugins: [<ids from the index>] mcp: [<ids from the index>] persona: <one id, optional> success_criteria: - <statement the agent verifies before finishing> ``` Rules the lint enforces — violating them makes the save fail: - ONE task, `type: harness`, `goal: "{input}"` (the per-run input), `mission:` as a multi-line `|` block that ends with the task_complete sentence above. - `allowed_tools` MUST include `task_complete`. Keep `ask_user` when clarification may be needed mid-run. Do not list a tool you did not discuss. - No `memory_owner`. No hardcoded emails or ids in the YAML — use `{input}`. - Omit `skills:` / `plugins:` / `mcp:` / `persona:` entirely when you declare none. Arrays REPLACE, never merge. - `agent:` is optional. Leave it out unless the user asks for a specific loop runtime. ## The fence — pick from these 24 tools only Files: `read_file write_file edit_file delete_file list_files search_files` (workspace only). Research: `web_search web_fetch`. Capabilities: `load_skill` (read a skill/plugin body), `memory` (durable facts), `knowledge` (user's knowledge base), `recall recall_history` (own past runs), `skill_manage` (author a skill — gated `ask` by default). Platform: `registry_search registry_lookup call_agent` (run any registry agent — fence it with `allowed_agents`), `invoke_workflow`, `delegate` (parallel sub-agents), `run_python`, `local_agent` (user's own machine; needs `local: true`, bots only). Human: `ask_user`, `platform_action`. Exit: `task_complete` (always). There is NO `denied_tools`. Deny = leave it out of `allowed_tools`, or `permissions: {tool: deny}`. Gate = `permissions: {tool: ask}` (the run pauses for approval). `allowed_agents: [ids]` fences `call_agent`; `'all'` opens the catalog minus `denied_agents` — money/blockchain agents stay denied unless named. ## Discovery rules - Agents: `registry_search` with a natural-language capability, then `registry_lookup` the exact id before declaring it in `allowed_agents`. - Skills / plugins / MCP servers: ONLY ids from AVAILABLE CAPABILITIES. A plugin brings its bundled skills and MCP servers; do not also list them one by one. - Models: leave `model:` out (platform default) unless the user names one. - Outside Studio: connect the MCP server at `https://mcp.plungeai.com/v1`, discover agent ids with `plungeai_list_agents {search: "<capability in plain words>"}`, then run the same YAML with `plungeai_execute_workflow`. ## Examples of good bounds - Research verifier: `allowed_tools: [web_search, web_fetch, task_complete]`, `effort: standard`, criteria "every verdict cites a primary source". - Ops helper that may act: `[registry_search, registry_lookup, call_agent, ask_user, task_complete]`, `allowed_agents: [gmail-agent, slack-agent]`, `permissions: {call_agent: ask}`. - Analyst with code: `[web_search, web_fetch, run_python, write_file, read_file, task_complete]`, `python_executor: auto`, `effort: deep`. Read [`references/harness-task.md`](/skills/plungeai-agentic-agent/references/harness-task) for every field and [`references/fence.md`](/skills/plungeai-agentic-agent/references/fence) for tool guidance when a case is not covered above. ## Reference pages <CardGroup cols={2}> <Card title="The fence — tools, agents, and fan-out guards" icon="file-text" href="/skills/plungeai-agentic-agent/references/fence"> allowedtools is a hard whitelist — only listed tools ever reach the LLM; an out-of-fence call is refused by the runtime, not merely discouraged. </Card> <Card title="Harness task — the full mission contract" icon="file-text" href="/skills/plungeai-agentic-agent/references/harness-task"> In a saved agentic agent: memoryowner is forbidden (tenancy comes from the executing user); local / localagents are bot-only and require agent: harness-agent. </Card> </CardGroup> # The fence — tools, agents, and fan-out guards Source: https://docs-preview.plungeai.com/skills/plungeai-agentic-agent/references/fence <!-- sources-of-truth: agents/agents/harness-agent/tools.ts (ALL_TOOLS), agents/agents/harness-agent/config.ts (DEFAULT_FENCE), agents/agents/harness-agent/agentic-loop.ts (fence enforcement, permissions) | last-synced: 2026-09-23 --> ## The tool fence `allowed_tools` is a hard whitelist — only listed tools ever reach the LLM; an out-of-fence call is refused by the runtime, not merely discouraged. Omit it and the loop runtime applies its own **fail-closed default fence**. The full loop-tool catalog (fence vocabulary): `read_file`, `write_file`, `edit_file`, `list_files`, `search_files`, `delete_file`, `web_search`, `web_fetch`, `load_skill`, `memory`, `knowledge`, `skill_manage`, `recall`, `recall_history`, `delegate`, `local_agent`, `registry_search`, `registry_lookup`, `call_agent`, `invoke_workflow`, `run_python`, `ask_user`, `platform_action`, `task_complete`. Fence design rules: - **Always include `task_complete`** — it is how a run ends cleanly. - Smallest set that can achieve the goal. A verification mission needs `web_search, web_fetch, task_complete` — not the file tools. - `ask_user` keeps human-question continuations available on every surface; include it when the goal may need clarification mid-run. - Two loop runtimes exist: the default full-surface runtime (all 24 tools; in unattended runs — the engine/bot default — `platform_action` is stripped from that *default* fence, which is why a scheduled mission can behave differently from the same mission run interactively) and `universal-agent` (thin default fence: the registry triad `registry_search` + `registry_lookup` + `call_agent`, plus research + `load_skill` + `ask_user` + `task_complete` — an unfenced universal-agent mission CAN call registry agents) — select with `agent:` on the harness task. An explicit `allowed_tools` always wins over either default. ## The agent fence and money-class protection `call_agent` lets the loop invoke registry agents. `allowed_agents: [a, b]` limits it to those; `'all'` opens the catalog minus `denied_agents`. **Payment/blockchain-class agents stay deny-unless-explicitly-named even under `'all'`** — naming them is the only way a mission can touch money, and `permissions: {call_agent: ask}` adds a human gate on top. This is a trust fence: surface refusals, never work around them. ## Recursion and fan-out guards - `delegate` spawns parallel child agents; children get a minimal default tool set and ALWAYS have `delegate`, `invoke_workflow`, and `memory` stripped — no fan-out explosions, no child memory writes. - Orchestrator depth is propagated (`depth` → children send `depth+1`) and hard-capped (default max depth 3); a too-deep dispatch is refused. - `max_parallel` caps one delegate call's width by refusal, never by serializing — silent batching would multiply wall clock. # Harness task — the full mission contract Source: https://docs-preview.plungeai.com/skills/plungeai-agentic-agent/references/harness-task <!-- sources-of-truth: orchestration/cnl-engine/harness-mission.ts, orchestration/cnl-engine/schema-types.ts (InlineMission), orchestration/cnl-engine/validate.ts, core/core-base/effort-presets.ts | last-synced: 2026-09-02 --> ## Full field reference | Field | Type | What it bounds | |---|---|---| | `goal` | string | The per-run input — becomes the agent's prompt | | `mission` | multi-line string | Standing purpose → system-prompt frame. A SINGLE-TOKEN string is a card reference instead (below) | | `persona` | string | One voice per run (`digital_twin` alias; `personas: [x]` → first entry) | | `skills` | string[] | Instruction packs — first 5 eager, rest on demand (`skills.md`) | | `experts` | string[] | Domain lenses — first 3 eager (`experts-personas.md`) | | `backgrounds` | string[] | Ambient context cards — first 3 eager, injected first | | `plugins` | string[] | Bundles: skill index + MCP servers + scripts (`plugins.md`) | | `mcp` | string[] | MCP server ids connected in-loop | | `model`, `provider` | string | Model/provider override (`models.md`) | | `effort` | `quick`\|`standard`\|`deep` | Turn-budget preset: **4 / 12 / 20** turns | | `max_turns` | number | Explicit loop cap (alias `max_iterations`); wins over `effort`; runtime default 50 | | `max_parallel` | number | Widest fan-out one `delegate` call may spawn — cap-and-refuse, never silently batched | | `allowed_tools` | string[] | The tool fence (below) | | `allowed_agents` | string[] \| `'all'` | Agent fence for `call_agent` | | `denied_agents` | string[] | Subtracted from the agent fence | | `permissions` | map tool → `allow`\|`ask`\|`deny` | Per-tool human gate: `ask` pauses the run with `needs_approval` before the tool executes; `deny` rejects the call | | `success_criteria` | string[] | Self-checked statements the agent verifies before finishing | | `instructions` | string | Extra author instructions, appended after skills — always lands | | `python_executor` | `auto`\|`pyodide`\|`anthropic`\|`gemini` | `run_python` tier routing | | `memory_owner` | string | Memory namespace override — per-bot isolation (`memory.md`) | | `local`, `local_agents` | bool, string[] | Local bot: actions route to the user's own machine via the desktop daemon (cloud brain, local hands); requires a connected local node | In a saved agentic agent: `memory_owner` is forbidden (tenancy comes from the executing user); `local` / `local_agents` are bot-only and require `agent: harness-agent`. ## Validation Studio applies at save (validate.ts:221-311) - `goal` required (`prompt:` is an alias); `mission` (text or object) OR `mission_ref` required. - `allowed_tools` must be an array; `max_turns` a positive number; `effort` ∈ quick|standard|deep. - `skills / experts / backgrounds / plugins / mcp` must be string arrays; `persona` one string. - Ids are NOT checked at save — an unknown id degrades to a warning at run time. Declare only listed ids. - Merge order when a card is referenced: card → workflow → task, last wins; arrays replace. # plungeai-bot-agent Source: https://docs-preview.plungeai.com/skills/plungeai-bot-agent Design and emit ONE PlungeAI (Ocean Studio) bot agent — a scheduled, unattended `type: harness` mission that reports to the user's channels (in-app, email, Slack, Telegram, WhatsApp, Discord) — as CNL YAML plus a bot-config block (cron schedule, delivery targets, optional run-on-my-computer). Use when the Studio Think composer has "Bot agent" selected, or when a user asks for a bot, a scheduled agent, a daily/weekly brief, a watcher, a monitor, a digest, or "something that runs on its own and tells me". Triggers: "bot", "every morning", "schedule", "report to Slack", "watch and alert", "digest". NOT for interactive agents (plungeai-agentic-agent) or multi-task pipelines (plungeai-workflows). [Download zip](https://skills.plungeai.com/plungeai-bot-agent.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-bot-agent/SKILL.md) <Note> Used by Studio: Ocean Studio's agent builder loads this skill by its id. </Note> A bot is an agentic agent with three extra facts: WHEN it runs, WHERE the result goes, and whether its hands are the user's own computer. Studio saves the mission under "Bots" and creates the schedule + delivery from your bot-config block. Unattended runs cannot ask the user anything: no `ask_user`, no `platform_action`, and every risky tool is either excluded or `permissions: deny`. ## The conversation (before any YAML) 1. **Job.** One sentence: what the bot produces each run (a brief, an alert, a digest). 2. **Cadence.** Ask for the schedule in words, propose the cron, confirm it. Five fields, UTC unless the user gives a timezone (convert and say so). 3. **Where it reports.** Ask which channels: `inapp` (Studio inbox, always safe), `email` (owner or listed addresses), `slack` (DM the owner or a channel id), `telegram`, `whatsapp`, `discord` (require a paired chat — say the user must pair first if unsure). Default `inapp` when the user has no preference. 4. **Hands.** Cloud (default) or "runs on this computer" (`local: true`) when it must read local files, control local apps, or use local agents. Local bots pin `agent: harness-agent`. 5. **Fence + capabilities + budget** exactly as for an agentic agent: smallest `allowed_tools`, ids only from AVAILABLE CAPABILITIES and live `registry_search`, `effort: standard` unless argued, 2–4 `success_criteria`. Confirm, then emit BOTH blocks. ## Output contract — two fenced blocks, in this order ```yaml workflow: name: "<short bot name>" description: "<one line: what it reports and how often>" tasks: - type: harness id: bot agent: harness-agent goal: "{input}" mission: | You are <name>, a bot that <job>. Each run you <steps in 2–4 sentences>. Output <format: bullets / table / one paragraph>. Keep it under <n> words. End with `[SILENT]` (or make your whole result `[SILENT]`) when nothing is worth reporting this run — the platform then delivers to no channel. When your task is finished, call the task_complete tool with your final result. effort: standard allowed_tools: [web_search, web_fetch, task_complete] success_criteria: - <statement the bot verifies before finishing> ``` ```bot-config schedule: "0 7 * * 1-5" deliver: - channel: inapp - channel: slack chat_id: C0123ABCD local: false prompt: "<the per-run input the schedule sends as {input}>" ``` Rules the lint enforces — violating them makes the save fail: - ONE task, `type: harness`, `agent: harness-agent`, `goal: "{input}"`, mission ends with the task_complete sentence. - `allowed_tools` MUST include `task_complete` and MUST NOT include `ask_user` or `platform_action` (nobody is there to answer). `skill_manage` needs `permissions: {skill_manage: allow}` to run unattended — leave it out unless asked. - No `memory_owner` (the platform scopes bot memory itself). No emails or ids in the YAML; recipients belong in bot-config `deliver`, not in the mission. - `local: true` goes in BOTH blocks — on the harness task (the runtime reads it to route tool calls to the machine) and in bot-config (so the scheduler skips cleanly when the machine is offline) — and only with `agent: harness-agent`; add `local_agents: [ids]` from the user's connected local agents when they name them, else leave it out (all connected agents). ## bot-config fields - `schedule` — 5-field cron, required. Examples: `0 7 * * 1-5` weekdays 07:00, `*/30 * * * *` every 30 min, `0 18 * * 5` Fridays 18:00. - `deliver` — list of `{channel, chat_id?, to?, phone_number_id?}`: `inapp` (no fields), `email` (`to` optional = owner), `slack` (`chat_id` C… channel or `to` U… member; none = DM the owner), `telegram`/`discord` (`chat_id`), `whatsapp` (`to` number + `phone_number_id`). Default `[{channel: inapp}]`. - `local` — `true` only for run-on-my-computer bots. Default `false`. - `prompt` — the per-run input. Default empty (the mission's goal alone drives the run). - `budget_usd_run` / `budget_usd_month` — optional non-negative spend caps. Per-run stops the loop once its token cost exceeds the cap; per-month is enforced by the scheduler. - `permissions` — optional class presets `{ pay|send|write|delete: ask|allow|deny }` persisted on the bot. `pay: ask` is the safe default for anything money-adjacent. `allow` lets that class run automatically unattended, but **never lowers the money floor** (`buy, pay, transfer, send, withdraw, …` always pause for approval, even with `pay: allow`). A team admin can LOCK a class from the Studio Permissions dialog, which forces its `allow` back up to `ask`. ## Permissions — approval rules Per-tool `permissions` on the mission gate individual tools. Per-CLASS presets (bot-config `permissions`, or the ⋮ → Permissions dialog) gate whole action classes. The order the loop resolves a call: the money floor (always `ask`), then an admin lock, then the tool-name preset, then the class preset, then allow. Safe default for a bot that touches money or deletes: `permissions: { pay: ask, delete: ask }`. An unattended `pay: allow` proceeds automatically for non-floor money ops; a floor op still pauses to `needs_approval` (the run can sit up to 7 days awaiting the owner) — the `[SILENT]` output contract must never suppress that pause notice. ## The fence for unattended runs Allowed vocabulary is the same 24 loop tools as an agentic agent; read `plungeai-agentic-agent` for the catalog. Bots add these rules: exclude `ask_user`, `platform_action`; prefer read paths (`web_search web_fetch read_file recall_history knowledge`) plus the agents the job needs via `call_agent` with a tight `allowed_agents`; anything that sends or pays needs the user's explicit yes in the conversation AND stays `permissions: deny` unless they insist. Delivery of the result is NOT a tool — the platform delivers `task_complete`'s result to the `deliver` targets. Read [`references/bot-config.md`](/skills/plungeai-bot-agent/references/bot-config) for delivery pairing and the platform behaviour on failure. Outside Studio the same bot ships over MCP (`https://mcp.plungeai.com/v1`): `plungeai_schedule` with `action: create`, `job_type: workflow` creates the job against a saved workflow. Discover the agent ids you fence into `allowed_agents` live — `plungeai_list_agents` from a client, or `registry_search` inside the loop — never from memory. ## Reference pages <CardGroup cols={2}> <Card title="bot-config → scheduler job" icon="file-text" href="/skills/plungeai-bot-agent/references/bot-config"> Studio turns the block into one scheduled job: jobtype: workflow, target: <workflow id>, schedule: <cron>, parameters (JSON) { prompt, deliver, local }. </Card> </CardGroup> # bot-config → scheduler job Source: https://docs-preview.plungeai.com/skills/plungeai-bot-agent/references/bot-config <!-- sources-of-truth: orchestration/scheduler/delivery.ts, orchestration/scheduler/types.ts (CreateJobRequest), apps/ocean-studio/src/components/scheduler/deliveryTypes.ts, apps/ocean-studio/src/worker/lib/botConfig.ts, orchestration/BOT-README.md | last-synced: 2026-09-02 --> Studio turns the block into one scheduled job: `job_type: workflow`, `target: <workflow id>`, `schedule: <cron>`, `parameters` (JSON) `{ prompt, deliver, local }`. The scheduler runs the saved workflow at each tick and delivers `task_complete`'s result to every target. ## Delivery behaviour (delivery.ts) - 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. ## Local bots `local: true` marks the job so the scheduler skips cleanly when the owner's machine is offline instead of failing. The reasoning loop stays in the cloud; only tool calls reach the machine through the desktop daemon. ## What the block does NOT do - Channel *binding* (a chat that forwards every message to the bot) is a chat-side command (`/bot <name>` on Telegram/WhatsApp/Discord, `/plunge bind` on Slack), not part of creation. - Inbound email / webhook triggers are attached later from the bot's ⋮ menu in Studio. # plungeai-campaign-agent Source: https://docs-preview.plungeai.com/skills/plungeai-campaign-agent Design and emit ONE PlungeAI (Ocean Studio) campaign agent — a long-running, list-driven, resumable agent that works an owned ledger of items in short scheduled runs until the current cycle is exhausted — as CNL YAML (a claim task plus a `type: batch` with `ledger: campaign`) and a campaign-config block (list source, cycle, schedule, max_attempts, then, deliver). Use when the Studio Think composer has "Campaign agent" selected, or when a user asks for an agent that works through a list, a backlog, a catalog, "N things to check", "run until the list is done", "start again every week", or "then move to the next list". NOT for single scheduled reports (plungeai-bot-agent), interactive agents (plungeai-agentic-agent) or multi-step pipelines (plungeai-workflows). [Download zip](https://skills.plungeai.com/plungeai-campaign-agent.zip) · [View raw SKILL.md](https://skills.plungeai.com/plungeai-campaign-agent/SKILL.md) <Note> Used by Studio: Ocean Studio's agent builder loads this skill by its id. </Note> A campaign is a task list with an owner. Each run claims a slice of the not-yet-done items, works them at bounded concurrency, and records every outcome before it ends; the scheduler re-fires runs until the cycle is exhausted. Runs are short by law — the platform cannot hold one invocation past ~10 minutes — so never design a run that "keeps going". Repetition is the schedule's job, resumption is the ledger's job. ## The conversation (before any YAML) 1. **Unit.** What is one item? A product, a lead, a URL, a document. Name the key that identifies it. 2. **List source.** Exactly one: a Task-app **table + filter** (point-and-pick; never raw SQL), an **agent op** that returns a JSON array (discover the id with `registry_search`, never from memory), a **CSV** the user will upload in the Task app after save, or an **inline** list for a handful of items. 3. **Per-item job.** A plain agent op when the item is "call one agent, store one row" (cheapest). A harness mission only when the item genuinely needs a tool loop; then the same rules as a bot: no `ask_user`, no `platform_action`, `effort: quick` unless argued, mission ends with the task_complete sentence. The job MUST upsert by `{item.key}` + `{item.cycle}` — say so in the mission or pass both to the op. 4. **Cycle.** `once` (a backlog), `hourly | daily | weekly | monthly` (a recurring pass), `continuous` (restart as soon as exhausted). `cycle_start: reset` reuses the same keys; `refill` re-queries the source. 5. **Schedule.** When runs may happen — a 5-field cron. Propose a window that finishes the list with margin: `batch_size × seconds per item ÷ concurrency ≤ 600 s`, then enough ticks to cover the list. 6. **Deliver.** Where the cycle summary and alerts go — same channels and pairing rules as a bot. Confirm, then emit BOTH blocks. ## Output contract — two fenced blocks, in this order ```yaml workflow: name: "<short campaign name>" description: "<one line: what one item is and how often the list is worked>" 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 # or type: harness when a tool loop is needed id: one agent: <agent id> operation: <op> key: "{item.key}" cycle: "{item.cycle}" ``` ```campaign-config list: table: { project: <project>, table: <table>, filter: { <column>: <value> }, key: <column> } cycle: weekly cycle_start: refill schedule: "*/5 9 * * 1" max_attempts: 2 then: "" deliver: - channel: inapp local: false ``` Rules the lint enforces — violating them makes the save fail: - Exactly one top-level claim task (`agent: data-table-agent`, `operation: campaignClaim`) and exactly one `type: batch` with `items_from: claim`, `ledger: campaign`, and `concurrency` ≤ 5. - Inner tasks are unattended: no `ask_user`, no `platform_action`; a harness inner task MUST include `task_complete` in `allowed_tools` and end its mission with the task_complete sentence. - The per-item task must reference `{item.key}` (warning if it looks insert-only — the ledger is at-least-once). - `max_attempts` is required. No `memory_owner`. No emails or ids in the YAML — recipients belong in `deliver`. - `local: true` only with a harness inner task pinned to `agent: harness-agent`, and in BOTH blocks. ## campaign-config fields - `list` — one of `table {project, table, filter, key}`, `agent {id, operation}`, `csv: true`, `inline: [...]`. - `cycle` — `once | hourly | daily | weekly | monthly | continuous`. Calendar cycles never restart inside their bucket. - `cycle_start` — `reset | refill`. Default `refill` for table/agent sources, `reset` for csv/inline. - `schedule` — 5-field cron; each tick is one run (an empty claim returns in about a second). - `max_attempts` — dead-letter threshold on explicit failures; required. - `then` — optional campaign id to start when a cycle completes. Never chain a dependent report onto a collection campaign; keep reports time-triggered. - `deliver` — as for bots (`inapp`, `email`, `slack`, `telegram`, `whatsapp`, `discord`). - `local` — run-on-my-computer, as for bots. Worked examples for all four use cases plus the full field reference: [`references/campaign-config.md`](/skills/plungeai-campaign-agent/references/campaign-config). Outside Studio the same campaign ships over MCP (`https://mcp.plungeai.com/v1`): `plungeai_schedule` with `action: create`, `job_type: workflow` creates the scheduler job against the saved campaign workflow. Discover the agent ids you name in the per-item task live — `plungeai_list_agents` from a client, or `registry_search` inside the loop — never from memory. ## Reference pages <CardGroup cols={2}> <Card title="campaign-config reference" icon="file-text" href="/skills/plungeai-campaign-agent/references/campaign-config"> A campaign-config fenced block sits after the CNL YAML. Studio parses it to open the ledger and create the scheduler job. Fields: </Card> </CardGroup> # campaign-config reference Source: https://docs-preview.plungeai.com/skills/plungeai-campaign-agent/references/campaign-config <!-- sources-of-truth: agents/agents/campaign-agent/campaign-agent-design-5.0.md §8, agents/agents/campaign-agent/EXAMPLES.md, apps/ocean-skills/skills/plungeai-bot-agent/references/bot-config.md (deliver section) | last-synced: 2026-09-08 --> A `campaign-config` fenced block sits after the CNL YAML. Studio parses it to open the ledger and create the scheduler job. Fields: | Field | Required | Meaning | |---|---|---| | `list` | yes | Where 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, …]`. | | `cycle` | yes | Calendar bucket: `once` \| `hourly` \| `daily` \| `weekly` \| `monthly` \| `continuous`. | | `cycle_start` | when re-listing | `refill` (add new list rows, keep prior) or `reset` (fresh cycle from the list). | | `schedule` | yes | Cron for the run cadence, e.g. `"*/5 9 * * 1"`. The scheduler re-fires until the cycle drains. | | `max_attempts` | yes | Per-item retry cap before an item is marked `failed` (integer ≥ 1; the ledger column defaults to 2). | | `then` | no | Campaign id to hand the baton to when this one's cycle completes. | | `deliver` | no | Channels for the cycle-complete notice (see below). | | `local` | no | `true` runs items on the user's own computer. | | `max_items` | no | Hard cap on total items claimed across the cycle. | | `task_types` | no | Per-row task/worker overrides (§8a). | | `learn` | no | Enables 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 <!-- copied verbatim from plungeai-bot-agent/references/bot-config.md deliver section --> - 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 <!-- copied verbatim from agents/agents/campaign-agent/EXAMPLES.md --> ### 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. ```yaml 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}" ``` ```campaign-config 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. ```yaml 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] ``` ```campaign-config 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. ```yaml 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] ``` ```campaign-config 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). ```campaign-config 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 ``` # Changelog Source: https://docs-preview.plungeai.com/resources/changelog <Info> Planned: not available yet. Tracked as TI-30. </Info> ## What this will do This page will list PlungeAI changes newest first, one dated entry per release day, each linking the pages that describe it. The dated entries are not published yet. ## Use this today <Card title="MCP guide: versions and what changed" icon="book" href="https://mcp.plungeai.com/docs#010-versions-and-what-changed"> The MCP server versions and recent changes. </Card> <!-- placeholder-source: content/_placeholders.json -->