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

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

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, Teams) — 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 (opens in a new tab) · View raw SKILL.md (opens in a new tab)

Used by Studio: Ocean Studio's agent builder loads this skill by its id.

A bot is an agentic agent plus three facts: WHEN it runs, WHERE the result goes, and whether its hands are the user's own computer. Studio saves it under "Bots" and creates the schedule and delivery from your bot-config block. Unattended runs cannot ask anything: no ask_user, no platform_action, every risky tool excluded or permissions: deny.

The conversation (before any YAML)

  1. Job. One sentence: what each run produces (a brief, an alert, a digest).
  2. Cadence. Ask for the schedule in words, propose the cron, confirm it (five fields); set timezone (IANA, e.g. Europe/Berlin) in the block to the user's zone, never convert to UTC.
  3. Where it reports. inapp (Studio inbox, always safe), email, slack, telegram, whatsapp, discord (these three need a paired chat: tell the user to pair first), teams (needs the owner's Microsoft connection). Default inapp.
  4. Hands. Cloud (default) or "runs on this computer" (local: true): local files, local apps, local agents. Both run on agent: one-agent.
  5. Fence, money, spend. Smallest allowed_tools; ids only from AVAILABLE CAPABILITIES and live registry_search; effort: standard unless argued; 2–4 success_criteria. Ask what the bot may never do alone (pay, send, delete) and what a run may cost.

Confirm, then emit BOTH blocks.

Output contract — two fenced blocks, in this order

workflow:
  name: "<short bot name>"
  description: "<one line: what it reports and how often>"
  tasks:
    - type: harness
      id: bot
      agent: one-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>
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 save lint enforces — violating them fails the save:

  • ONE task, type: harness; a present allowed_tools MUST include task_complete; no memory_owner.
  • posture, peers, review, max_runtime_s and workspace apply only on agent: one-agent; on harness-agent, agentic-agent or universal-agent they fail the save, not ignored.
  • A local: true bot must name agent: one-agent; put local: true in BOTH blocks (task and bot-config, so the scheduler skips cleanly when the machine is offline) and add local_agents: [ids] only when the user names them.

Also expected: agent: one-agent, goal: "{input}", a mission ending with the task_complete sentence, no emails or ids in the YAML (recipients go in deliver), no ask_user / platform_action (nobody answers). skill_manage needs permissions: {skill_manage: allow} unattended: omit it unless asked.

bot-config fields

  • schedule — 5-field cron, required (0 7 * * 1-5 weekdays 07:00, */30 * * * *). Optional timezone (IANA).
  • deliver — list of {channel, chat_id?, to?, phone_number_id?}: inapp (none), email (to optional = owner), slack (chat_id C… or to U…; none = DM the owner), telegram/discord (chat_id), whatsapp (to + phone_number_id), teams (chat_id = the Graph chat id; posts as the owner through their Microsoft connection; text capped at 4000 characters).
  • local, prompt (the per-run input; default empty).
  • budget_usd_run, budget_usd_month — USD caps above 0, at most 100000; 0 is refused, omit the key for no cap.
  • permissions — class presets {send|write|pay|delete: allow|ask|deny|hand_off} stored on the bot.
  • peers, posture, review, max_runtime_s, workspace, max_turns, skills, persona, allowed_tools — the mission keys below, written onto the task. memory_consolidate: weekly — opt-in weekly memory consolidation.

Mission keys (on the harness task, snake_case)

KeyValueEffect
postureread_onlydenies write, send, delete, pay, delegate, invoke_workflow, every MCP tool
peers[bot name | id | "a2a:<url>"]the only bots message_bot may reach; none by default
reviewautoa model reviews each allowed write/send/pay/delete call (one extra call each)
max_runtime_ssecondswall-clock cap; the run stops with timeout
workspacebot | runbot (default for a saved bot) keeps files across runs; run starts clean
budget_usd_runUSDstops the loop at the next turn once cost passes it
permissions{class or tool: allow|ask|deny|hand_off}see Permissions
allowed_toolslistthe fence; opt-in tools below
skills, personaidscapability injection
max_turnsnumberturn cap (effort sets a default)

An off-contract posture or review is forced to read_only / auto: it never widens a run.

Permissions and budgets

Classes: send, write, pay, delete (reads are always allowed). Presets: allow, ask (the run pauses needs_approval, up to 7 days), deny, and hand_off: the call never runs and does not retry; the result ends with [handed off to you — not run: …] so the owner does it themselves (a leading [SILENT] is dropped). Use hand_off for what a bot should prepare but never do (pay: hand_off). A call resolves: read-only posture, then deny, then hand_off, then the money floor (buy, pay, transfer, send, withdraw, … always ask, even with pay: allow), then the tool-name preset, then the class preset, then allow. An unknown preset is ask. A team admin can LOCK a class: its allow rises to ask (never lifts a deny). Locks live on the saved bot, not in YAML. Three denied calls in a row stop an unattended run (stop_reason: denied). hand_off is one-agent only (other runtimes get deny); the task's permissions:, bot-config permissions and the permissions verbs all accept it. Safe default: permissions: { pay: ask, delete: ask }.

Budgets: budget_usd_run caps one run; budget_usd_month (bot-config, Studio, or the verbs below) is enforced by the scheduler. The lower of the YAML and the stored per-run cap applies, and a capped run's result says so. Blank or omitted = no cap; the block and Settings refuse 0, and the verbs clear a cap with null / none — never send 0 (the runtime ignores it).

Always-on abilities (opt-in)

Add to allowed_tools only what the job needs; each needs a saved bot.

  • schedule — action: create | list | pause | resume | delete | run_now | wake. create {name, cron, timezone?, prompt?, deliver?, ends_at?}; one run at a clock time is cron @once with run_at (ISO-8601 with offset); wake {in, note} re-runs the bot once (min 60 s). The bot writes the cron and says it back in words; 50 live jobs per bot.
  • message_bot — {to, text, wait?}; to is in peers, or group:<name> (the sender must be a member of that group; wait: true is refused for a group). Replies arrive as [MESSAGE from <bot>] at the start of a later run; wait: true runs the peer now as a plain child (no memory, inbox, workspace). A bot group (2–6 of the owner's bots, made in Studio or via the verbs) fans a message out: membership is the fence, every other member's inbox gets it, the next member wakes, 8 hops max.
  • browser — {steps, url?, session?: 'bot' | 'none'}; 'bot' keeps cookies. Click, type and key steps count as writes.
  • memory — action: forget {query} purges matching entries.
  • code — {prompt, directory?, session_id?, timeout_s?} hands one turn (max 300 s) to the owner's OceanCode over the Local Tunnel. Class write; no daemon connected, no tool.
  • mcp_tool_search — only with MCP servers attached: past 15 tools or 8 KB, schemas are listed by name and a search loads up to 5 for the next turn (never ones the permissions refuse).

Shared bots: inbox, schedule, message_bot, the browser session and workspace are owner-only; a teammate runs a shared bot without identity.

Channels in

A chat can be bound to a bot (Telegram, WhatsApp, Discord, Teams): /bot <name> in the chat (Slack: /plunge bind), or the verbs below; pair first (Teams two-way chat also needs the platform's Teams app registration). Voice notes (Telegram and WhatsApp only, up to 25 MB) from an authorised sender are transcribed with Whisper and answered like text (as audio where the channel can); Discord and Teams are text only.

Outside Studio — the same bot over REST, MCP and CLI

REST https://api.plungeai.com (One API 2.3.0, live contract GET /v1/openapi.json), MCP https://mcp.plungeai.com/v1, CLI ocean-cli.

JobRESTMCPCLI
policy, locks, capsGET/PUT /v1/workflows/{id}/permissionsplungeai_workflow permissions_get / permissions_setworkflows permissions get|set --class pay=ask --lock pay --budget-run 0.5 --budget-month 20
workspace filesGET …/workspace-files, …/download?path=files / fileworkflows files <id> [--download <path> --out <file>]
inboxGET …/inboxinboxworkflows inbox <id>
chat bindingsGET/POST …/bindings, DELETE …/bindings/{channel}/{sender_id}, POST /v1/channels/pairbindings / bind / unbindworkflows bindings list|bind --channel telegram --sender <id>|unbind --channel --sender --yes
groups/v1/bot-groups, /{id}, /{id}/threadgroups / group_set / group_delete / group_threadbot-groups list|create --name --members a,b|update|delete|thread <id>
steer or list a run's filesPOST /v1/executions/{id}/steer, GET …/filesplungeai_executions steer / filesexecutions steer <id> <text>, executions files <id>
schedule once, wakePOST /v1/schedules (@once + run_at), …/{id}/wakeplungeai_schedule run_at, wakeschedules create NAME --type workflow --target <id> --cron @once --at <iso>, schedules wake <job_id> --note

A saved bot runs under its stored policy on every door, including the Agent Call door: POST /v1/execute {"agent": "<bot id>@3", "input": "…"}.

The fence for unattended runs

Same 24 loop tools as an agentic agent (plungeai-agentic-agent) plus the always-on ones above. Leave out ask_user and 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 deny/hand_off/ask. Delivery is NOT a tool: the platform sends task_complete's result to the deliver targets (references/bot-config.md: limits, pairing). Discover agent ids live (plungeai_list_agents, registry_search), never from memory.

Reference pages

Planned: TI-34

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