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

# Bots

> A bot is a saved workflow that runs a One Agent loop on a clock, answers messages, keeps its own memory and files, and stays inside a policy you set.


A bot is a saved workflow with `kind: bot`. Its one task is a [One Agent loop](/one-agent/loop-mode) with a mission. It is not a separate runtime: what makes it a bot is the wiring around the YAML, which is where the schedule, the chats, the triggers, the policy and the budget live.

| A bot has | Set by | Page |
|---|---|---|
| A mission and a tool fence | The YAML | [Playbook reference](/bots/playbook-reference) |
| A clock | `schedule` tool, a schedule on the bot | [Schedules and wake](/bots/schedules-and-wake) |
| Teammates | `peers`, bot groups, A2A | [Bot to bot and groups](/bots/bot-to-bot-and-groups) |
| Chats and a web widget | Pairing and bindings | [Channels and voice](/bots/channels-and-voice) |
| Rules and a spend cap | Stored presets, locks, budgets | [Permissions and budget](/bots/permissions-and-budget) |
| Files, an inbox and memory | `workspace`, `memory` | [Workspace and inbox](/bots/workspace-and-inbox) |
| Outside events | Webhook, email, Slack, Gmail, Git | [Triggers and hooks](/bots/triggers-and-hooks) |
| A control surface on every door | REST, MCP, CLI | [REST, MCP and CLI](/bots/rest-mcp-cli) |

## A minimal bot

```yaml
workflow:
  name: Competitor Watch
  description: Checks a page for pricing changes
  tasks:
    - type: harness
      id: watch
      agent: one-agent
      goal: "Check {input} for pricing changes"
      max_iterations: 8
      allowed_tools: [web_search, web_fetch, task_complete]
      mission: |
        You are Competitor Watch. Reply NO-CHANGE when nothing changed.
        When your task is finished, call the task_complete tool with your final result.
```

Save it as a bot over REST:

```bash
curl -s -X POST https://api.plungeai.com/v1/workflows \
  -H "Authorization: Bearer $PLUNGE_API_KEY" -H 'Content-Type: application/json' \
  -d '{"name":"Competitor Watch","kind":"bot","yaml":"workflow:\n  name: Competitor Watch\n  tasks:\n    - type: harness\n      id: watch\n      agent: one-agent\n      goal: \"Check {input} for pricing changes\"\n      allowed_tools: [web_search, web_fetch, task_complete]\n      mission: |\n        You are Competitor Watch. Reply NO-CHANGE when nothing changed.\n        When your task is finished, call the task_complete tool with your final result.\n"}'
```

In Studio, choose **New**, then **Bot agent**; the bot opens in the same YAML editor as a flow. The bot templates (`GET /v1/templates?kind=bot`) are ready-made starting points; `POST /v1/templates/{id}/use` copies one into your account.

## What a save checks

Saving runs the CNL schema and then the kind lint, before anything is written. A refusal is `422 invalid_workflow` with `errors` and `warnings`, and the stored row is unchanged.

- A bot is exactly one task, and it is `type: harness`.
- A declared `allowed_tools` fence must include `task_complete`. A mission that never mentions `task_complete` is a warning.
- `memory_owner` is refused: a bot's memory tenant comes from the user who runs it.
- A local bot (`local: true` or `local_agents`) should set `agent: one-agent`. `harness-agent` and `agentic-agent` are still accepted until the switch-over; `universal-agent` never is.
- `posture`, `peers`, `review`, `max_runtime_s` and `workspace` apply only on `agent: one-agent`. On `harness-agent`, `agentic-agent` or `universal-agent` they are an error, because those runtimes would ignore them.
- A hard-coded email address or UUID in the YAML is a warning.

## Identity and who may use what

When a saved bot runs, the engine tells the loop which bot it is (`bot_id`) and who owns it (`bot_owner`). The inbox, the `schedule` and `message_bot` tools, the `browser` bot session and the persistent workspace need that identity.

- These abilities belong to the owner. A teammate who runs a shared bot runs it without an identity.
- A saved workflow that is not a bot but uses `agent: one-agent`, run by its owner, is treated like a bot.
- Deleting a bot deletes its scheduled jobs and wipes its own memory namespace (the one a web widget uses). What the bot saved with `memory` while you ran it lives in your own memory and stays; remove it with `POST /v1/memory/forget`.

## Every run uses the stored policy

The engine loads the bot's stored policy once per run, on every door: a run by id, a schedule, a trigger, a chat message, MCP and Studio all stop at the same caps and holds. See [Permissions and budget](/bots/permissions-and-budget).
