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

# Harness task — the full mission contract

> Bot-only keys (peers, posture, review, maxruntimes, workspace, permissionlocks) are plungeai-bot-agent's.


<!-- 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-10-05 -->
## 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`), a positive number with no runtime ceiling; wins over `effort`; runtime default 50 |
| `max_tokens` | number | Per-turn output token budget for the loop's model calls |
| `budget_usd_run` | number | Per-run spend cap in USD, above 0 (omit for no cap); the loop stops at the next turn once cost passes it |
| `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 or class (`send`, `write`, `pay`, `delete`) → `allow`\|`ask`\|`deny`\|`hand_off` | Per-tool or per-class gate: `ask` pauses the run with `needs_approval` before the tool executes; `deny` rejects the call; `hand_off` never runs it and tells the owner it is theirs to do (`one-agent` only; elsewhere it becomes `deny`) |
| `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 |

Bot-only keys (`peers`, `posture`, `review`, `max_runtime_s`, `workspace`, `permission_locks`) are `plungeai-bot-agent`'s. In a saved agentic agent: `memory_owner` is forbidden (tenancy comes from the executing user); `local` / `local_agents` are bot-only. Always name `agent: one-agent` (cloud and local alike) — a harness task with no `agent:` still lands on the legacy `harness-agent` id until the switch-over.

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