Modes
A mode is a named overlay on a session that changes how the agent works:
which tools it may call, an extra piece of system prompt, and per-mode limits. An
app declares its modes under runtime.modes; the session is always in exactly
one mode at a time. The classic pair is Plan (read-only: investigate and
propose) and Build (full access: implement) - but modes are general, and you
can define whatever set fits the app.
Two things can change the active mode:
- The user, via the mode picker in the composer.
- The agent itself, mid-turn, with the
change_modetool - but only when the app opts in withruntime.agent_can_switch_mode: true(see below).
Declaring modes
runtime:
default_mode: plan # which mode a fresh session starts in
agent_can_switch_mode: true # let the agent switch modes itself (opt-in)
modes:
plan:
label: Plan
description: "Read-only: investigate and propose."
icon: lightbulb
system_prompt: "You are in PLAN mode. Investigate and propose; do not edit."
tool_grants:
- module: filesystem
tools: [read, glob, grep]
build:
label: Build
description: "Full access: implement the plan."
icon: wrench
Each mode (ModeDef) accepts, all optional:
| Field | What it does |
|---|---|
label | Human name shown in the picker (defaults to the mode id, capitalised). |
description | One line explaining the mode. |
icon, accent | UI hints for the picker. |
system_prompt | Extra system prompt appended for this mode - "you are in PLAN mode, do not edit". |
tool_grants | The tools this mode allows (same shape as capabilities.grant). Omit it for full access. |
max_turns, timeout | Per-mode overrides of the runtime defaults. |
behavior_profile | Switch the behavior profile for this mode. |
runtime.default_mode names the starting mode; if omitted, the first declared
mode is the default.
How tool_grants filters tools
A mode's tool_grants is a ceiling on what the agent may call while in that
mode:
- Present → the agent is restricted to exactly those tools. Everything else is blocked for that mode (a blocked call returns a clear "not available in this mode" error to the agent). This is how Plan stays read-only.
- Absent → the mode does not restrict; the agent keeps its full tool surface. This is how Build gets full access.
The final tool surface is the intersection of three things: the app's grants, the
agent's own agents[].modules allowlist (if any),
and the active mode's tool_grants. Meta-tools (ask_user, change_mode,
…) are always available regardless of mode.
Letting the agent switch modes
Set runtime.agent_can_switch_mode: true and the agent is given a change_mode
tool automatically. The system also tells the agent, each turn, which modes exist
and that it can switch - you do not write that into the prompt yourself; it is
generated from the real declared modes.
The agent calls change_mode(mode: "build"). Then:
- The user sees a confirmation bar above the composer ("the agent is switching from Plan to Build") with a short window to cancel. If they cancel, the switch is refused and the agent is told so; the mode is unchanged.
- Otherwise the switch applies, mid-turn: from the next step of the same turn, the agent runs under the new mode's tools and limits - so it can finish planning and then immediately start building, without waiting for a new message.
This is opt-in per app because a mode switch changes the whole turn (which tools
are allowed, the prompt). Leave agent_can_switch_mode off and only the user can
switch.
If Plan is read-only and you want the agent to be able to leave it, you must set
agent_can_switch_mode: true. change_mode itself is never blocked by a mode's
tool_grants (it's a meta-tool), so a read-only mode can't strip the agent's
only way out.
A working app
Plan/Build for a coding agent. Compiles as-is (the brain uses a Digitorn gateway model - no API key of your own needed):
app:
app_id: coder
name: Coder
runtime:
entry_agent: main
default_mode: plan
agent_can_switch_mode: true
modes:
plan:
label: Plan
description: "Read-only: investigate and propose."
icon: lightbulb
system_prompt: "You are in PLAN mode. Investigate and propose; do not edit."
tool_grants:
- module: filesystem
tools: [read, glob, grep]
build:
label: Build
description: "Full access: implement the plan."
icon: wrench
agents:
- id: main
system_prompt: "You help with code. In Plan, investigate and propose. When the plan is ready, switch to Build and implement it."
brain:
provider: openai
backend: openai_compat
model: mimo-v2.5-free
config:
api_key: placeholder
tools:
modules:
filesystem: {}
bash: {}
capabilities:
default_policy: auto
Related
- Agents - Tool surface - the per-agent
modulesceiling that combines with modes - Security / capabilities -
tool_grantsshares thecapabilities.grantshape - Behavior -
behavior_profileper mode