pub enum Cmd {
Show 58 variants
CallModel {
turn: TurnId,
request: ChatRequest,
},
CompactConversation {
turn: TurnId,
request: CompactionRequest,
},
ExecuteTool {
turn: TurnId,
call_id: ToolCallId,
source: ToolCall,
model_id: String,
safety_mode: SafetyMode,
plan_file: Option<PathBuf>,
plan_permissions: PlanPermissions,
context_percent: Option<u8>,
intent: Option<String>,
session_id: String,
message_index: usize,
scratchpad: Option<PathBuf>,
},
CancelScope(TurnId),
BackgroundScope(TurnId),
ResolveApproval {
call_id: ToolCallId,
decision: ApprovalChoice,
},
ResolveQuestion {
call_id: ToolCallId,
resolution: QuestionResolution,
},
SyncTaskStore(TaskStore),
PersistPlanConfig(PlanConfig),
UserTaskEdit(UserTaskEdit),
NotifyTaskCompleted {
task: TaskItem,
completed: u32,
total: u32,
},
EnsureScratchpad {
session_id: String,
},
ListScratchpad {
path: PathBuf,
},
SaveConversation(ConversationHistory),
SaveCompactionArchive {
archive: CompactionArchive,
record: CompactionRecord,
conversation: ConversationHistory,
},
SaveProcess(ManagedProcess),
PersistLastModel(String),
PersistReasoningFor {
model_id: String,
level: ReasoningLevel,
},
PersistOllamaNumCtxFor {
model_id: String,
num_ctx: Option<u32>,
},
PersistOllamaOffload(bool),
PersistUiTheme(ThemeChoice),
ListMemory,
RememberMemory {
text: String,
},
ForgetMemory {
id: String,
},
ConsolidateMemory {
model_id: String,
},
LoadConversation(String),
ListConversations,
ListProjectFiles,
ListRuntimeTasks {
limit: usize,
},
LoadRuntimeTask {
id: String,
},
ListRuntimeProcesses {
limit: usize,
},
ShowRuntimeProcessLogs {
id: String,
},
StopRuntimeProcess {
id: String,
},
KillBackgroundAgent {
agent_id: Option<String>,
},
RestartRuntimeProcess {
id: String,
},
OpenRuntimeTarget {
target: String,
},
ShowRuntimePorts,
ListRuntimeApprovals,
DecideRuntimeApproval {
id: String,
decision: String,
},
ListRuntimeCheckpoints {
limit: usize,
},
ListForkCheckpoints {
session_id: String,
message_index: usize,
},
ListRuntimePlugins,
UpdateRuntimeTaskStatus {
id: String,
status: TaskStatus,
final_report: Option<String>,
},
CreateRuntimeCheckpoint {
paths: Vec<PathBuf>,
},
RestoreRuntimeCheckpoint {
id: String,
},
ShowRuntimeModelInfo {
model: String,
},
InitMcpServers(HashMap<String, McpServerConfig>),
StopMcpServer {
name: String,
},
PullOllamaModel {
model: String,
},
ProbeVision {
model_id: String,
warn: bool,
},
OpenInSystem(PathBuf),
WriteImageToTemp {
path: PathBuf,
bytes: Vec<u8>,
format: String,
},
ReadClipboard,
CopyToClipboard(String),
ComposeInEditor {
text: String,
},
Exit,
SetTerminalTitle(String),
AlertUser,
}Expand description
A single side-effect request. Most variants are one-shot; CallModel
and ExecuteTool spawn long-running tasks inside a per-turn
TurnScope.
Variants§
CallModel
Dispatch the next chat request. Effect runner maps this onto
ModelProvider::chat for the session’s active provider.
CompactConversation
Generate a compact context checkpoint without continuing into a normal assistant turn.
ExecuteTool
Run one tool in parallel with any other tools in the same turn.
The runner wires ExecContext::token to the turn’s scope so
Cmd::CancelScope aborts them all at once.
model_id is the active session’s model id at the moment this
tool call was emitted. The runner passes it into ExecContext
so tools like SubagentTool can spawn children against the
same provider the parent is using.
Fields
call_id: ToolCallIdsafety_mode: SafetyModeEffective live safety mode at the moment this call was emitted
(state.session.safety_mode, floored to ReadOnly while a plan
is being drafted). The runner builds the policy gate / Auto
classifier from this rather than the static config.
plan_file: Option<PathBuf>Some(path) while the session is in plan mode: the one path the
policy gate exempts from the read-only floor, and the flag the
plan carve-outs (memory writes, known-safe builds) key on.
plan_permissions: PlanPermissionsLIVE per-category plan permission levels (/plan config edits
them mid-session; the startup Config snapshot in ExecContext
would go stale). Only consulted while plan_file is Some.
context_percent: Option<u8>Context-window fill at dispatch, when known. exit_plan_mode
shows it on the clear-context option so the tradeoff is legible.
intent: Option<String>The user’s stated intent for the turn (latest user message), passed to the Auto-mode classifier as alignment context.
session_id: StringConversation id at dispatch — checkpoint-anchoring provenance
(rides into ExecContext and onto any checkpoint this call takes).
CancelScope(TurnId)
Cancel every task in the given turn’s TurnScope. After the
scope’s JoinSet drains (bounded by a ~2s timeout), the runner
emits a single Msg::TurnCancelled(turn) — that, not
Msg::StreamDone, is the terminal event that lets the reducer
transition Cancelling → Idle. A same-id Msg::StreamDone that
races the drain does NOT end the turn: handle_stream_done only
acts on a Generating turn and restores the prior state
(Cancelling) otherwise, so TurnCancelled stays the one
terminal signal for a cancel.
BackgroundScope(TurnId)
Ctrl+B: signal the turn’s scope to BACKGROUND (not cancel) its running
work. The scope’s background token fires; detachable tools (execute_
command) move their child to a background process and return. The scope
is left intact (unlike CancelScope).
ResolveApproval
Resolve an inline approval prompt: deliver the user’s decision to the
parked tool task via the ApprovalBroker. NOT turn-scoped — it’s a
fire-and-forget to the broker (the tool task it unblocks is the
turn-scoped work).
ResolveQuestion
Resolve an ask_user_question prompt: deliver the user’s answers to the
parked tool task via the QuestionBroker. Like ResolveApproval, a
fire-and-forget to the broker (not turn-scoped).
SyncTaskStore(TaskStore)
Overwrite the effect-side TaskBroker store. Emitted where the
reducer changes checklist truth outside the broker’s own publish
cycle: rewind/fork and /clear (both clear it) and --replay
re-seeding. Fire-and-forget to the broker, not turn-scoped.
PersistPlanConfig(PlanConfig)
Persist the [plan] table to the user config file (the /plan config picker edits live state; this writes it through the
key-scoped updater so unrelated keys and defaults stay unfrozen).
UserTaskEdit(UserTaskEdit)
A user /tasks edit. Routed through the effect runner to the
TaskBroker (the single writer) instead of mutating reducer state
directly, so a concurrent tool call can’t clobber it; the broker’s
Msg::TasksUpdated publish brings the result back.
NotifyTaskCompleted
A task transitioned to completed: run the gated task_completed
plugin hook. A denying hook flips the task back to in_progress via
the broker and queues a notice for the model’s next turn.
EnsureScratchpad
Materialize the per-session scratch directory for this conversation
id (creating it under the private temp dir + stamping its pid lock),
then report the path back via Msg::ScratchpadReady. Emitted at
startup and whenever the conversation id changes (/clear, /load,
rewind fork). The handler also opportunistically sweeps stale sibling
scratchpads. Fire-and-forget, not turn-scoped.
ListScratchpad
/scratchpad — list the session scratch directory’s contents back
into the transcript (bounded ASCII listing via Msg::RuntimeText).
Only emitted while Session::scratchpad is stamped; carries the
path so the effect never re-derives it. Fire-and-forget.
SaveConversation(ConversationHistory)
Save the current conversation to disk. No-op if unchanged since last save (effect-side idempotence).
SaveCompactionArchive
Persist the raw messages removed by a compaction, then the compacted (message-stripped) conversation. Both are written by ONE effect task, archive first — only overwriting the conversation if the archive persisted — so a failed/lagging archive can never lose messages while the stripped conversation is saved over the old one.
SaveProcess(ManagedProcess)
Persist a daemon-visible background process record.
PersistLastModel(String)
Persist the active model ID as last_used_model.
PersistReasoningFor
Persist reasoning level tied to a specific model ID.
PersistOllamaNumCtxFor
Persist (or clear, when num_ctx is None) a per-model Ollama num_ctx
override set via /context <n>/max/auto.
PersistOllamaOffload(bool)
Persist the Ollama RAM-offload toggle (/context offload on|off).
PersistUiTheme(ThemeChoice)
Persist the /theme choice as ui.theme in the user config file.
ListMemory
List saved memories; emits Msg::RuntimeText with the rendered list.
RememberMemory
Save free-text to private memory; emits Msg::MemoryChanged + status.
ForgetMemory
Delete a memory by name/id; emits Msg::MemoryChanged + status.
ConsolidateMemory
Model-assisted prune of duplicate/obsolete memories, reversible via a
checkpoint. Emits Msg::RuntimeText (the report) + Msg::MemoryChanged.
LoadConversation(String)
Load a specific conversation by ID and emit
Msg::ConversationLoaded. Reducer consumes that event to
replace the current session.
ListConversations
Scan the conversations directory for the /load picker. Emits
Msg::ConversationsListed with one ConversationSummary per
saved session (newest first). The reducer transitions to
UiMode::ConversationList and the render shows the picker.
ListProjectFiles
Walk the project for the @-mention file picker (gitignore-aware,
capped, sorted). Emits Msg::ProjectFilesListed with relative paths
(directories carry a trailing /).
ListRuntimeTasks
List durable daemon/runtime tasks.
LoadRuntimeTask
Load one durable daemon/runtime task and its timeline.
ListRuntimeProcesses
List durable daemon/runtime background processes.
ShowRuntimeProcessLogs
Print one durable process log into the conversation.
StopRuntimeProcess
Stop a durable process by pid.
KillBackgroundAgent
Cancel a detached background subagent (None = all of them). The
effect layer fires the kill token held by the SubagentSpawner; the
dying child reports back via Msg::BackgroundAgentFinished.
RestartRuntimeProcess
Restart a durable process using its recorded command/cwd.
OpenRuntimeTarget
Open a URL, path, or process target.
ShowRuntimePorts
Show listening ports.
ListRuntimeApprovals
List pending approval records.
DecideRuntimeApproval
Mark one approval as approved or denied.
ListRuntimeCheckpoints
List restore checkpoints.
ListForkCheckpoints
Query checkpoints of session_id anchored strictly past
message_index — fired by rewind/fork so the reducer can tell the
user which file checkpoints the discarded timeline left behind.
Replies with Msg::ForkCheckpointsFound.
ListRuntimePlugins
List installed plugins.
UpdateRuntimeTaskStatus
Update one durable task’s status.
CreateRuntimeCheckpoint
Create a shadow checkpoint for explicit paths.
RestoreRuntimeCheckpoint
Restore files from a shadow checkpoint.
ShowRuntimeModelInfo
Show provider/model capability information.
InitMcpServers(HashMap<String, McpServerConfig>)
Start every configured MCP server; each one emits
Msg::McpServerReady or Msg::McpServerErrored as it comes up.
StopMcpServer
Stop a running server (e.g. config was removed, or app quit).
PullOllamaModel
ollama pull <model> with progress → Msg::ModelPullFinished.
ProbeVision
Probe whether model_id advertises the vision capability (Ollama
/api/show) → Msg::ProviderVisionResolved. warn rides through so the
reducer nags only when an image is actually in play (a paste, or a
/model switch with an image already staged); the probe always refreshes
the capability snapshot regardless.
OpenInSystem(PathBuf)
xdg-open / open / start on a file path. Used by the
image-paste preview and the “open in editor” affordance.
WriteImageToTemp
Persist a pasted image to a temp file so the TUI can open it
via OpenInSystem. Emits no follow-up Msg on success; failure
is a log-and-drop.
ReadClipboard
Read the system clipboard on a blocking task. The per-platform
dispatch (xclip / wl-paste / pngpaste / PowerShell) can block
for hundreds of ms on macOS via osascript, so it never runs on
the reducer thread. Always emits Msg::ClipboardRead(..) —
Image/Text on success, Empty/Error otherwise — so the
paste-race guard sees every read resolve.
CopyToClipboard(String)
Write text to the system clipboard on a blocking task (mirrors
ReadClipboard’s per-platform dispatch). Used by in-app drag-select
copy. Emits a Msg::TransientStatus (“Copied N chars” / failure).
ComposeInEditor
Suspend the TUI and open $VISUAL/$EDITOR on the input draft
(Ctrl+O / /editor). Intercepted by the interactive run loop — it
owns the terminal and event stream — and never reaches the effect
runner there; headless drivers log-and-drop it. The round-trip
resolves as Msg::EditorReturned.
Exit
Exit the main loop. No reply message — the loop observes
state.should_exit after the reducer returns and breaks out.
SetTerminalTitle(String)
Write the OSC 2 terminal-title sequence. Reducer diffs
against ui.last_title_dispatched so this only fires on
actual title changes, not every frame.
AlertUser
Ring the terminal bell (BEL) to draw the user’s attention — emitted on run completion / a pending approval only while the terminal is unfocused. Suppressed in headless mode (same gate as the title).
Implementations§
Source§impl Cmd
impl Cmd
Sourcepub fn tag(&self) -> &'static str
pub fn tag(&self) -> &'static str
Human-readable tag, for tracing + replay logs. Stable across refactors (tests assert against it).
Sourcepub fn is_turn_scoped(&self) -> bool
pub fn is_turn_scoped(&self) -> bool
True iff this command needs to run inside a TurnScope so it
can be cancelled by Cmd::CancelScope. The effect runner uses
this to decide between “spawn into JoinSet” and “spawn detached”.
Sourcepub fn scope_turn(&self) -> Option<TurnId>
pub fn scope_turn(&self) -> Option<TurnId>
The TurnId of the scope this command would spawn fresh work
into. Only the scope-spawning variants return Some (the same
set as is_turn_scoped); the scope-control variants
(CancelScope / BackgroundScope) act on an existing scope
rather than populating one with new work, so they return None.
The effect runner uses this to refuse spawning fresh work for a
turn it has already cancelled (tombstoned) — a stray post-cancel
CallModel/ExecuteTool/CompactConversation would otherwise
resurrect an un-cancelled scope via scope_mut’s or_insert_with
(F38). CancelScope must keep working on a tombstoned turn, which
is exactly why it is excluded here.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Cmd
impl RefUnwindSafe for Cmd
impl Send for Cmd
impl Sync for Cmd
impl Unpin for Cmd
impl UnsafeUnpin for Cmd
impl UnwindSafe for Cmd
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more