Modes
Makima ships with two agent modes: build and plan. A mode bundles a badge in the input bar, a system-prompt snippet the model follows, and, optionally, a write restriction and its own visible toolset. This page shows what the built-in modes do, and how a Lua plugin defines a new mode or overrides a built-in one.
The built-in modes
Tab toggles between them (build is the default).
- build
[BUILD]- the default. Full toolset, no restrictions. - plan
[PLAN]- analyse and plan. Writes are locked to a single plan file, and the model gets a directive telling it never to touch anything else.
Switching to plan mode allocates a plan file under plans/. The write and
edit tools only allow edits to that file while in plan mode.
What a mode is
Under the hood a mode is a definition in a shared registry:
- name (
"build","plan", or a custom id) and a label for the badge. - system_prompt - a snippet appended to the system prompt, like the plan
directive.
{plan_path}and the other prompt variables are filled in. - restrict_write_to (optional) - when set, every non-matching write is blocked, exactly like the plan-file-only rule.
- tools (optional) - when set, the model sees only this exact toolset for
that mode. When absent, the mode inherits the default (build) set. This is how
a tool like
plan_submitexists only while you are in plan mode.
The built-in build and plan are pre-registered entries. Overriding one is
the same call as defining a new mode: it fully replaces the definition.
Defining and overriding modes from Lua
The registry lives on the API as maki.api.mode. Define a mode or override a
built-in with define:
maki.api.mode.define({
name = "audit", -- a new custom mode
label = "[AUDIT]",
system_prompt = [[You only review code. You never change it.]],
restrict_write_to = "audit.md",
tools = { "read", "grep", "glob", "write", "edit" },
})
Override the built-in plan mode the same way:
-- Replaces the built-in plan directive and toolset.
maki.api.mode.define({
name = "plan",
label = "[PLAN]",
system_prompt = function(ctx)
return "My stricter plan-mode directive, plan file: " .. (ctx.plan_path or "?")
end,
tools = { "read", "grep", "glob", "write", "edit", "plan_submit" },
})
system_prompt may be a string or a function of { cwd, plan_path } returning
a string. Because a definition fully replaces the built-in, a partial override
(for example only tools, no system_prompt) drops the built-in directive;
supply both when you override.
Other methods:
maki.api.mode.get() -- current mode id: "build", "plan", or a custom name
maki.api.mode.set("plan") -- enter a mode; fails if it is not defined
maki.api.mode.list() -- all modes as { name, label }
maki.api.mode.reset("plan") -- drop a plugin override, restore the built-in
maki.api.mode.reset() -- restore every built-in
Switching modes fires the autocmd ModeChanged with data { mode = "<id>" }.
Example: a plan-review workflow
The repositories ship two example plugins that put this together. They are
bundled and enabled by default; disable the ones you don't want from init.lua:
maki.setup({
plugins = {
mode_plan_override = { enabled = false },
plan_submit_tool = { enabled = false },
},
})
mode_plan_overridereplaces the built-inplanmode with a verbatim clone of polytoken's plan directive (via theplanplugin override). It focuses the model on producing a reviewable artifact, restricts writes to the plan file, swaps the toolset to read tools pluswebfetch,write/edit/plan_submit, and adds/planand/buildslash commands. The directive and the plan reviewer splice one shared plan specification, so both always see the exact same document.plan_submit_toolis a mode-scoped tool: it prints the finished plan inline as a display-only message (kept out of your context) and surfaces the plan review form, with accept (hands off to implementation), refine (keep planning), or cancel. It only exists in plan mode because plan's toolset lists it. Whileplan_submitis in an active mode's toolset, the built-in auto-hooks that open the review form on a plan-file write are skipped; the model callsplan_submitexplicitly when the plan is ready.
The built-in task tool grows a plan_reviewer subagent type when the plan
override is active: a read-only audit that verifies the plan follows the shared
plan specification, maps every acceptance criterion to a named test, and checks
test-infrastructure adequacy before answering VERDICT: pass|fail. It is only
spawnable inside plan mode, and general subagents are blocked there so plan
work stays read-only. A reviewer finding about a missing test harness is handled
by revising the plan to build the infrastructure, confirmed via the question
tool when the gap is out of scope.
With all three enabled, a typical loop is:
- Switch to plan mode (
/plan). The model draftsplan.mdusing the cloned directive and the reduced toolset. - The model calls
taskwithsubagent_type = "plan_reviewer"to audit the plan, then iterates untilVERDICT: pass. - The model calls
plan_submit; the plan prints inline and you accept, refine, or concede through the plan review form. - Switch to build mode (
/build) to implement with the full toolset.
Persistence and other surfaces
The active mode is persisted with the session, so a custom mode survives a restart (it falls back to build with a warning if its plugin is not loaded then). Custom modes also appear in the Agent Client Protocol session modes when the ACP server is started from a live plugin host.