Live-session feedback (a real Zed elicitation round-trip): the model presented its finished plan as a plain reply and asked the USER to switch modes — the exact reversal the roadmap warns about — because the shipped section's 'present it with the exit_plan_mode tool' read as a suggestion. The section now says a finished plan is delivered by calling exit_plan_mode, preferred over pasting it as a plain reply or asking the user to switch modes — firmer, without imperatives. ask_user_question enters the shipped plan allowlist (asking is read-only-safe), and the section points a blocked decision at it. The plan-acp-agent example composes the bash family (default mode only — plan's allowlist keeps excluding it, so the two modes now demo a real difference) plus tool-ask-user; both recorded scenarios re-recorded: the pin now shows plan = [ask_user_question, exit_plan_mode, read, todo_write] and post-exit default = the full eight-tool surface.
mode/ — session-mode policy family
Session modes: named, logged, per-agent policy states, with plan mode as the first shipped definition. A single product package — there is no interface/implementation seam here, because a mode's variable parts are config values (allowlist, section text), not swappable implementations.
| Package | Role | ctx key |
|---|---|---|
mode/ |
mode/set vocabulary + fold, the ctx.modes service (list/get/set with the turn-boundary flush), the soft layer (assemble filter + mode:policy section), the hard layer (tools/pre-execute deny-by-default gate), and the model-facing exit_plan_mode review tool |
ctx.modes |
The mode in force is a pure function of the session log (SessionEventMap['mode/set'], last one wins), so resume and fork restore it with no extra machinery; the default mode is the absence of policy, keeping the plugin invisible until a mode is set. UIs read flips off session/event: the stdio app exposes /mode, the ACP bridge maps the vocabulary to the session-mode picker. RFC: plan mode.