Skip to content

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 runPlanMode filters via PLAN_MODE_TOOLS in services/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_config carries per-workspace rows. The row's mode column holds the slug; allowed_tools is the tool subset; system_prompt is the appended fragment.
  • Runtime: when a chat message arrives, the engine resolver loads the chat's mode, looks up the workspace's mode_tool_config row, and assembles the effective prompt as BASE_PROMPT + MODE_PROMPT + WORKSPACE_OVERRIDE. The tool registry is filtered through the row's allowed_tools.
  • Built-in handlers: modes/agent.ts runs the write-capable loop (used by Build mode and any custom mode flagged as write-capable). modes/plan.ts runs the analyse-only loop with PLAN_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, see plan.ts:141-155).
  • Defaults: when no mode_tool_config row 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:

  1. The API loads the chat's mode and the workspace's mode_tool_config.
  2. engine-resolver.ts builds the effective prompt: BASE_PROMPT + MODE_PROMPT + WORKSPACE_OVERRIDE.
  3. The tool loader filters the global tool list by the mode's allow-list.
  4. docore opens (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.ts into 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.

See also