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

# 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).


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` (`one-agent` when it uses the always-on
  abilities below), `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. On `agent: one-agent` the order is deny first, then the money
floor, then `ask`, then the tool preset, then the class preset, then allow; an admin lock only lifts
`allow` to `ask`. 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.

## Always-on abilities (`agent: one-agent`)

When the user wants the bot to manage its own schedule, talk to other bots, browse a site it logs
in to, or run under tighter controls, emit `agent: one-agent` (instead of `harness-agent`) on the
harness task and use these. All are opt-in; leave them out unless the user asks.

- **Tools** (add to `allowed_tools`, each needs a saved bot):
  - `schedule` — `action: create | list | pause | resume | delete | run_now | wake`. `create {name,
    cron | '@once', in?, timezone?, prompt?, deliver?, ends_at?}`; `wake {in, note}` re-runs the bot
    once (at least 60 s). The bot writes the cron itself and must say the schedule back in words.
  - `message_bot` — `{to: <bot name | id | 'a2a:<url>'>, text, wait?: boolean}`. `to` must be in
    `peers`. Replies are asynchronous: they reach the sender as `[MESSAGE from <bot>]` at the start
    of a later run (`wait: true` runs the bot now instead).
  - `browser` — `{steps, url?, session?: 'bot' | 'none'}`; `session: 'bot'` keeps the bot's cookies
    between runs. Steps that click, type or press keys count as writes.
  - `memory` — `action: forget {query}` removes matching memory entries.
- **Mission keys** (on the harness task, snake_case): `peers: [bot names | ids | "a2a:<url>"]` (the
  only bots `message_bot` may reach; none by default), `posture: read_only` (denies write, send,
  delete, pay), `review: auto` (a model reviews each allowed write / send / pay / delete call; costs
  one call each), `max_runtime_s: <seconds>` (wall-clock cap), `workspace: run | bot` (default
  `bot` for a saved bot: its files persist across runs; `run` starts clean).
- **Limits to know:**
  - `message_bot wait: true` runs the target as a plain child run (depth + 1, `skip_memory`): no
    memory, no inbox, no bot workspace, no bot tools. Use `wait: false` for the full bot.
  - Shared bots: the always-on abilities (inbox, `schedule`, `message_bot`, the browser bot session,
    the persistent workspace) are owner-only; a teammate runs a shared bot without identity.
  - A saved non-bot workflow that uses `agent: one-agent` and is run by its owner is treated like a
    bot (persistent `bot:<id>` workspace by default, bot tools available): the engine derives the
    identity for every saved workflow.
  - `posture: read_only` also denies `delegate`, `invoke_workflow` and every MCP tool (an unknown
    class fails closed). An off-contract `posture` or `review` value is forced to `read_only` /
    `auto`; it never widens a run.

<!-- Author note: this body is stored in skill-memory; after editing it, re-push it (`npm run push:skill-memory`, see orchestration/BOT-README.md gap 1) or Bot agent composes without it. -->

## 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>
