Modes (Build / Plan / Chat)¶
A mode is a preset that swaps the system prompt and tool list for a chat session. Doable ships three:
| Mode | Purpose | Tools |
|---|---|---|
| Build | The default. The agent edits files, installs packages, and runs the dev server. | All write-capable tools |
| Plan | The agent analyzes the codebase and produces a written plan, but never modifies anything. | Read-only tools (read_file, list_dir, grep, fetch) |
| Chat | Free-form Q&A about the project. No tools. Cheapest in tokens. | None |
Modes are picked from a dropdown in the chat panel. The active mode is stored on the chat row (chats.mode).
Why modes?¶
- Safety: Plan mode lets non-developer stakeholders review the agent's intended changes before they touch code.
- Cost: Chat mode skips the long tool-list system prompt entirely.
- UX: Different prompts shape the AI's tone (terse vs verbose, code-first vs explainer-first).
Defining custom modes¶
Workspace admins can add their own modes from Workspace Settings → AI → Modes:
- Name: display label (e.g. "Refactor", "Docs writer").
- System prompt: appended to the base prompt.
- Allowed tools: checkbox list filtered from all available tools.
- Default model: optionally pin to a specific model.
The configuration is persisted in the mode_tool_config table (see packages/db/migrations/050_mode_tool_config.sql) and consumed by services/api/src/ai/modes/.
Custom modes per workspace¶
The built-in modes (Build, Plan, Chat) are the ones Doable ships. Workspace admins can layer workspace-scoped custom modes on top, without code changes. Each custom mode is a tuple of:
- A display name and slug.
- An additional system prompt fragment appended to the base prompt.
- A tool allow-list, computed against the global registry the same way
runPlanModefilters viaPLAN_MODE_TOOLSinservices/api/src/ai/modes/plan.ts. - An optional default model that pins the engine resolver to a specific provider + model for that mode.
How custom modes are wired:
- Storage:
mode_tool_configcarries per-workspace rows. The row'smodecolumn holds the slug;allowed_toolsis the tool subset;system_promptis the appended fragment. - Runtime: when a chat message arrives, the engine resolver loads the chat's
mode, looks up the workspace'smode_tool_configrow, and assembles the effective prompt asBASE_PROMPT + MODE_PROMPT + WORKSPACE_OVERRIDE. The tool registry is filtered through the row'sallowed_tools. - Built-in handlers:
modes/agent.tsruns the write-capable loop (used by Build mode and any custom mode flagged as write-capable).modes/plan.tsruns the analyse-only loop withPLAN_MODE_TOOLS = { read_file, list_files, search_files, ask_clarification, create_plan }. A custom mode that uses the agent handler can extend the tool list; a custom mode that uses the plan handler inherits the read-only enforcement (any tool outside the allow-list returns"Tool '<name>' is not available in plan mode"as a tool result, seeplan.ts:141-155). - Defaults: when no
mode_tool_configrow exists for a workspace, the shipped Build / Plan / Chat defaults apply.
Practical examples:
- "Refactor": agent handler, tools =
read_file, edit_file, search_files, grep, run_tests; prompt = "Make minimum-diff changes and run tests after each edit". - "Docs writer": agent handler, tools =
read_file, write_file, edit_file, list_files; prompt = "Write clear technical docs. Never modify source files." - "Audit": plan handler, default tools only; prompt = "Inspect the codebase and report security or correctness issues."
Switching modes mid-conversation still creates a fresh underlying session; the chat history persists, but the agent's working state (open files, intermediate planning) resets.
How a mode is applied at runtime¶
When a chat message comes in:
- The API loads the chat's
modeand the workspace'smode_tool_config. engine-resolver.tsbuilds the effective prompt:BASE_PROMPT + MODE_PROMPT + WORKSPACE_OVERRIDE.- The tool loader filters the global tool list by the mode's allow-list.
docoreopens (or resumes) the session with that prompt + tool set.
Switching modes mid-conversation creates a fresh session under the hood. The chat history persists, but the agent's working state is reset.
Plan-mode workflow¶
Plan mode is special enough to have its own UI. When the agent finishes producing a plan:
- The plan is parsed by
services/api/src/ai/plan-parser.tsinto a structured list of steps. - A "Run plan in Build mode" button appears.
- Clicking it switches to Build mode and feeds the plan back as the next user message.
This gives a clean review then execute flow that works well for non-developers.