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

# bot-config → scheduler job

> The block becomes one scheduled job that delivers taskcomplete's result to every target.


<!-- 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, apps/ocean-studio-stable/src/worker/lib/botConfig.ts, core/core-base/bot-policy.ts, orchestration/BOT-README.md | last-synced: 2026-10-05 | maintainers: this skill's body is stored in skill-memory — after editing it run `npm run push:skill-memory` (Bot agent composes without it; the pushed body must stay under 14000 bytes) -->

The block becomes one scheduled job that delivers `task_complete`'s result to every target.

## Where fields land, and their limits

An unknown key is ignored; a bad value fails the save with `bot-config.<key> …`.

| Field | Limit | Lands on |
|---|---|---|
| `max_runtime_s` | whole seconds (decimals rounded down), 10 to 86400 | the task |
| `max_turns` | whole number, 1 to 500 | the task |
| `skills`, `allowed_tools`, `peers` | at most 50 items, 256 characters each | the task |
| `persona` | at most 128 characters | the task |
| `budget_usd_run`, `budget_usd_month` | greater than 0, at most 100000 (0 is refused: a zero cap is ignored) | the bot |
| `permissions` | the four classes only, `allow\|ask\|deny\|hand_off` | the bot |
| `memory_consolidate` | `weekly` | a second job, Sundays 03:00 |

Task keys are written onto the saved task and win over the YAML. Budgets and class presets live on
the bot (Settings edits them; the engine folds them onto the task each run: YAML wins per class, the
lower per-run cap wins), so keep them out of the task YAML. The save lint, not the block, refuses
`allowed_tools` without `task_complete`.

## Delivery behaviour (delivery.ts)

- Fire-and-forget: a delivery failure never fails the run.
- Length caps (characters): telegram 3800, whatsapp 3800, discord 1900, slack 3800, email 100000,
  inapp 2000. Keep the output under the smallest cap you use.
- telegram / whatsapp targets must be paired to the owner (pairing code in Studio, `/pair <code>`
  from that chat; Telegram also needs the owner to have opened the bot once); discord needs any
  active pairing. Unpaired targets are skipped.
- email sends from the platform address; a bare target means the owner. Any other address
  delivers only after its holder confirmed it, else it is skipped silently.
- slack: a bare target DMs the owner; a `chat_id` / `to` target needs the owner to be a
  connected workspace member.
- teams: skipped without the owner's Microsoft connection; channel posts (`to: <teamId>/<channelId>`)
  are refused until the platform is granted the scope — use a chat id.

## What the block does NOT do

- Channel binding, inbound email / webhook triggers and outbound run hooks are attached after
  creation: the bot's ⋮ menu in Studio, `/v1/triggers/{webhook|email|hooks}`, `plungeai-scheduling`.
