A session runs on four settings: the model, its reasoning level, the operating mode and the permission mode, and on a fifth, the toolset, while the configuration has a toolset preset. Each of them can be changed from the conversation itself, with a slash command typed in any surface, for the rest of the session or only for the next few turns. The permission dialog can switch the session out of ask, and the agent changes the model or the reasoning level itself when the user asks it to, never on its own. Every change goes through one setter in the session manager (Manager.ApplySessionSettings, internal/session/settings.go), and every surface watching the session - the browser tab, a console, an editor - shows the new values.
| Command | Changes | Argument |
|---|---|---|
/model <id> |
the model | a configured model id |
/reasoning <level|off|default> (alias /effort) |
the reasoning level | a level the model offers; off turns thinking off, default goes back to the model's own level |
/think [level] |
turns thinking on | optional; without one, the model's default level, else medium |
/nothink (alias /no_think) |
turns thinking off | none |
/agent, /plan, /ask |
the operating mode | none |
/permissions <ask|accept_edits|bypass> |
the permission mode: when tools ask for approval | the mode; the console opens a picker without one |
/toolset <name|default> |
the toolset the session is offered its tools by | a toolsets[] preset; default for every tool of the mode; the console opens a picker without one |
/mode no longer exists, on any surface: next to /model in a menu it was one keystroke from the wrong command, and each mode now has a command of its own.
Every command takes --once or --count=N among its own words, which changes the setting for the next turn or the next N turns (at most 50) instead of for the session:
/model rpa/qwen3.8-27b --count=3
/nothink --once
/plan --once how would you split this package?
Commands are read only at the start of what you type, and several may follow one another, on one line or on consecutive ones. The first word that belongs to no command starts the prompt, and that prompt may itself be /compact, /export or a skill. A command in the middle of a sentence is prose, and so is anything a mention or a skill body brings in. A settings command wins over a skill of the same name. The registry is internal/session/commands.go.
A change without a flag is the session's and lasts until the next change. A change with --once or --count=N is counted in turns you start: each prompt you send takes one turn from every override, and that turn keeps the values for its whole length, including the steps after a queued follow-up and after a permission prompt. A background wake and a subagent's turn take nothing. A change for the session clears that setting's turn override, the running turn's included, so the last command you typed is the one that holds. Running a saved plan (Run plan, runPlanSlug) is such a change of the mode: it switches the session to agent mode and ends a mode override, /plan or /ask, so a plan is carried out in agent mode even while /plan --count=N has turns left. A session in ask mode refuses to run a plan, and a plan that an /ask turn only mentions stays reading material (Operating modes).
The model, the reasoning level (thinking switched off included) and the mode of a session are kept in its session.json. Its permission mode is kept there too (sessionPermissionMode), so a session switched to bypass for an unattended run is still in bypass after a restart of the console or of coddy serve. The permission mode is not in config.yaml: a new session starts in the mode chosen last on any surface - a session switched with /permissions, a selector, the permission dialog or PATCH /coddy/sessions/{id} - and in ask until anything was chosen. Coddy keeps that choice in ${CODDY_HOME}/permission-mode.json (Security and trust). A session keeps its own mode until it is switched itself, so a choice made later in another session does not move it, and a change with --once or --count=N is not a choice: it leaves the mode new sessions start in alone, and so does the console's --permission-mode launch flag, which sets only the session its run opens. Its turn overrides live in the process's memory: a restart forgets them. Until then they stay with the session, also while no surface holds it: the console lets go of a session on /new and /resume, and coming back to it brings its permission mode and its overrides back.
A message that is nothing but commands runs no turn. The settings are applied and the model sees nothing. The web UI and the console show the change on their selectors and footer; an editor, the Telegram bot and an HTTP client get a short notice of each change as the answer to the message, such as Model: rpa/qwen3.8-27b for the next 3 turns. The transcript keeps nothing of the exchange (What the transcript shows).
A message with text after the commands applies the session-wide changes and runs the text as a turn with the turn-scoped ones. The override travels with that prompt and is installed only once the turn is admitted, so a second tab or a background wake cannot take it first.
While a turn is running, a session-wide command applies at once and any text after it goes to the message queue as an ordinary follow-up. A turn-scoped command with text is refused there (409 turn_scoped_follow_up over HTTP), because the queued message can change mode or be cancelled before delivery, so the command has no stable target turn. A new model or reasoning level is used from the next model request of the running turn, never in the middle of a stream: the answer that was streaming when it changed is finished by the model that started it and stored under that model's name, and the transcript names the new model from the next answer on. The permission mode is read on every tool call; a new operating mode starts with the next turn. A subagent already running keeps what it was spawned with.
A model switched to has its context window read at once, the window its provider's model listing reports included, so the next request - the running turn's next step, or the first request of the next prompt - is measured against it. When the context crosses compaction.threshold_percent of the new window, it is compacted before that request (Compaction).
/nothink and /reasoning off are offered only when the model entry explicitly sets allow_reasoning_off: true. The default is false: Coddy cannot infer that a provider/model deployment honours the request, so the operator enables the choice only after verifying that deployment.
- Qwen3 models on an OpenAI-compatible server receive
chat_template_kwargs.enable_thinking: false; - Anthropic models with a thinking budget receive no thinking block, and Claude Opus 4.7, 4.8 and 5, Sonnet 5 and Haiku 5.5 receive
thinking: {"type": "disabled"}; - the Codex backend receives
none; - another provider/model deployment uses its existing
offmapping.
Claude Opus 5.5, Sonnet 5.5 and the Fable models always think: on a type: anthropic provider they never offer off, even with the opt-in, and a lower level is what makes them think less.
Without the opt-in, the command is refused with the levels the model does offer. An explicit empty reasoning_levels: [] hides the selector and off even when the opt-in is set. When you switch to a model that does not offer the stored level, the session runs at that model's default, and the selectors and the snapshot show the level actually used.
A toolsets[] preset narrows the tools a session is offered, for a small-window local model that should not carry the schemas of tools it never calls (Toolsets). A model names the toolset its sessions run with, and /toolset <name> picks another one for this session; /toolset default picks none, so the session is offered every tool of its mode whatever its model names. The pick is kept in the session's session.json and survives a restart and a switch of the model; a new session starts with the toolset of its model. /model <id> /toolset <name> switches both on one line.
The toolset is offered only while the configuration has a preset: the snapshot of the session's settings then carries toolset and toolsetChoices, the web composer shows a Toolset chip after the permission chip, the console's /toolset opens a picker and its footer names the preset, and an editor sees a Toolset option. Without a preset none of them is there, and a preset added to the configuration brings them without a restart: the server publishes the settings of every live session again.
While the session asks (ask), a permission prompt that belongs to the session itself carries one more choice: Bypass for this session (allow_session_bypass), and for a file write also Allow edits for this session (allow_session_accept_edits). The choice approves the call and switches the session, so the rest of the same turn runs without prompts; like any switch of a session, it also becomes the mode new sessions start in. A prompt relayed from a subagent, a prompt a hook forced, and a config_commit or config_rollback do not offer them; those two keep asking even under a bypass switched on in the session, because a commit can rewrite the permission policy itself.
The permission prompt of a session in ask: the session switch sits in red before Reject.
The agent changes its model or reasoning level with switch_model only when the user asks in the current conversation. It does not pick a different model or level for a difficult step or routine work on its own, and it names a summarizer for compact_context only when the user named one. A subagent is different: the agent may run a child on another model or reasoning level than its own, which is expected. The system prompt describes switch_model only in a turn that is offered it. The related settings have three sources:
- the
switch_modeltool sets the model, the reasoning level or both, from its next request. A user's request lasts for the session by default, like/model;scope: turnapplies only when the user limited the change to this turn or task. Its description lists the configured models with their levels, so the choice is made among what exists. It is offered in every mode when there is something to switch (more than one model, or one with reasoning levels), and never to a subagent; - a skill's frontmatter
modelandreasoning(aliaseffort) apply for the rest of the turn, whether you typed/skillor the model calledload_skill, unless the turn already runs on a value set for it by a command or byswitch_model(Skills); spawn_agenttakesmodelandreasoningfor the child, which the agent may pick itself, and a subagent definition takesreasoningnext tomodel; the child's model is the argument, then the definition's, then the parent's (Subagents).
A model id or a level the configuration does not offer is an error in a switch_model or a spawn_agent call, for the model to correct. In a skill or a definition file it is a warning in the agent log, and the session's own value stays.
A change you make shows where the surface keeps its settings: the composer's selectors and its line of overrides in the web UI, the footer of the console, the options of an editor. The transcript gets no line for it, whether it came from a selector, a command, the permission dialog, or --model and --mode at launch, coddy -p included: you made it, and it is on screen already.
A change the agent made itself is the one the transcript notes: its switch_model call, or a skill whose frontmatter names a model or a reasoning level. The web UI shows a SYSTEM row at the end of that turn and the console prints one line, both with the text of the change, such as Model: rpa/qwen3.8-27b for this session or Reasoning: off for the rest of this turn.
The agent switched the model on request; the SYSTEM row closing the turn is the only line a settings change leaves.
A session saved by an earlier version keeps a notice of every change in its ui_log.json. The web UI does not show the ones the agent could not have made: a mode, a permission mode, a change for a number of turns, and a model or a level set for the session in a turn without a switch_model call.
The composer's Mode, Permissions and Model selectors show the session's settings as the server has them. Entering a session shows its own mode, its model, its level (a session running with thinking off shows Off) and its permission mode, from the snapshot GET /coddy/sessions/{id}/messages answers with. What the start page picked, and the cookies coddy_llm_model and coddy_llm_reasoning that remember it, are the default of a new chat only: they never replace a session's value on screen, so they never ride into it with the next message. The reverse holds as well: a new chat starts in Agent with the default model and level, whichever mode, model and level the chat just left had, and also when the start page is reached with the Back button; a mode picked there creates the chat in it. A prompt carries the mode (the top-level model of POST /v1/responses), metadata.model and metadata.reasoning, and the server keeps what it is given, so while the opened session is loading and the selectors still show the session just left, Send and Enter wait for the session's own snapshot; a message for a running turn still joins the queue. A read that fails is tried again, and only a 404 from the server opens the address as a new chat. A session with no level of its own, on a model that names no reasoning_default, shows the level it runs at, medium or else the model's first level, and sends none with the next message, so it is not pinned to a level nobody picked. The Reasoning menu offers Off only when its logical model sets allow_reasoning_off: true. A setting the running turn holds (--once, --count=N) stays on the line of overrides, and the selectors keep the session's own value. The permission chip reads Ask first, Accept edits or Bypass, the last in red; a line next to the selectors lists what is changed for the next turns. The chip's tooltip names the mode new sessions start in. On the start screen, before the chat has a session, the chip reads that mode, the one chosen last on any surface: GET /coddy/info names it, and every settings snapshot carries it as configuredPermissionMode, so a session switched in another tab or in a console moves the chip as well. A mode picked there is sent with the first message as /permissions <mode> unless it is that mode, so an explicit Ask first while new sessions start in bypass is kept. While the page does not know that mode (a server that does not name it, a read that failed), the mode the chip shows is sent with the first message, so the first turn runs under what the operator saw. A change made anywhere else - a command, the dialog, a user-requested switch_model call, a console on the same session - reaches the tab as event: session_settings and moves the selectors. A browser that has not seen the latest change yet does not undo it when it sends: the request carries metadata.settingsVersion, and an older version leaves the session's settings alone.
The composer after the session was switched to bypass and the model changed for two turns: the selectors and the line of overrides show both changes, and the transcript has no line for them.
Typing / lists the commands with their arguments. Picking /model, /reasoning or /permissions opens that selector, and picking /agent, /plan or /ask switches the mode; typed out with a value and sent, the command goes to the server like any other prompt.
The slash menu names each command's argument and its --once|--count=N flags.
The console runs the same commands through the same parser. A bare /model, /reasoning or /permissions opens its picker. The footer shows the permission mode next to the folder, in the warning colour for bypass, and a line of the turn overrides under the model. Both belong to the session on screen: after /new or /resume the footer names the permission mode and the overrides of the session entered.
The console footer: the permission mode, and what is changed for the next turn and the next three.
--model, --mode and --permission-mode at launch set the same settings for the session the console opens, and --permission-mode leaves the mode new sessions start in alone. Under --remote every command changes the server's session, the permission mode included (Console).
An editor sends the commands as prompt text, and available_commands_update lists them with their argument hint (input.hint). The reasoning option is advertised in the ACP thought_level category, which a client may render as its thinking control, and the permission mode in _permission_mode, a category of Coddy's own that a client shows as a plain selector (Editors).
The bot passes /model <id>, /reasoning, /think, /nothink, /agent, /plan and /ask to the session; a command alone is answered with its notice, and a bare /model still opens its keyboard. /resume answers with the model and the reasoning level the resumed session runs on (default when neither the session nor its model names one), its own and not the model last picked on the bot, which only a fresh chat starts on. /permissions is not a bot command: the bot approves its chat agent's tools itself (Telegram gateway).
PATCH /coddy/sessions/{id} takes selectedModelId, selectedReasoning, mode and permissionMode, with turns for a change of that many turns, and answers with the session's settings snapshot. GET /coddy/sessions/{id}/messages returns the same snapshot, GET /coddy/commands lists the commands with their kind, argument hint and the values each one takes for the session, and a prompt of commands only is answered with coddy_meta.settings_only on POST /v1/responses (HTTP API).
The snapshot:
{
"sessionId": "sess_abc123def456",
"version": 42,
"model": "rpa/qwen3.8-27b",
"reasoning": "high",
"reasoningChoices": ["low", "medium", "high", "off"],
"mode": "agent",
"permissionMode": "bypass",
"configuredPermissionMode": "ask",
"overrides": [{ "setting": "model", "value": "rpa/qwen3.8-mini", "turnsLeft": 2 }]
}version orders the snapshots of the sessions of one process; a client keeps the highest it has seen. configuredPermissionMode is the mode a new session starts in, the one chosen last on any surface (ask until anything was chosen); the field kept its name from the time that mode came from the configuration. An override with active: true is held by the running turn.
Operating modes, Security and trust, Slash commands, Tools, Message queue.




