Skip to main content

SessionUpdate

Enum SessionUpdate 

Source
pub enum SessionUpdate {
Show 82 variants Spawning { key: SessionSlot, project_name: String, cwd: String, display_name: String, }, Connected { key: SessionSlot, session_id: SessionId, cwd: String, current_model: CurrentModel, available_models: Vec<AvailableModel>, mode: Option<ModeState>, history: Vec<Message>, dropped: usize, compaction_count: u32, }, CallOutput { key: SessionSlot, call_id: String, output: CallOutput, }, SessionReplaced { key: SessionSlot, session_id: SessionId, cwd: String, current_model: CurrentModel, available_models: Vec<AvailableModel>, mode: Option<ModeState>, history: Vec<Message>, dropped: usize, compaction_count: u32, }, Handoff { key: SessionSlot, handoff: HandoffRecord, }, MachineTurn { key: SessionSlot, machine: Option<MachineTurn>, }, ConnectionFailed { key: SessionSlot, message: String, fatal: bool, }, Releasing { key: SessionSlot, }, Notice { key: SessionSlot, severity: NoticeSeverity, text: String, }, SetModeFailed { key: SessionSlot, mode: PermissionMode, message: String, }, SetModelFailed { key: SessionSlot, model: String, message: String, }, PermissionRequest { key: SessionSlot, tool_id: String, request: PermissionRequest, }, QuestionRequest { key: SessionSlot, tool_id: String, request: QuestionRequest, }, PendingInteractionResolved { key: SessionSlot, tool_id: String, question_index: Option<u64>, answered_with: Option<String>, }, McpOperationError { key: SessionSlot, error: McpOperationError, }, TurnComplete { key: SessionSlot, terminal_reason: Option<TerminalReason>, }, TurnCancelled { key: SessionSlot, }, TurnError { key: SessionSlot, message: String, class: Option<TurnErrorClass>, terminal_reason: Option<TerminalReason>, }, ChatAppended { key: SessionSlot, msg: Message, source: Option<PromptSource>, }, HookObservation { key: SessionSlot, tool_use_id: Option<String>, permission_mode: Option<String>, effort: Option<String>, agent_id: Option<String>, agent_type: Option<String>, }, ForgeAccountIdentity { key: SessionSlot, display_name: String, }, DictateOverrides { key: SessionSlot, overrides: DictateOverrides, }, ContextUsageSnapshot { key: SessionSlot, percentage: Option<u8>, max_tokens: Option<u64>, }, McpSnapshot { key: SessionSlot, servers: Vec<McpServerStatus>, error: Option<String>, }, ProcessesChanged { key: SessionSlot, snapshot: ProcessSnapshot, }, MonitorsChanged { key: SessionSlot, monitors: Vec<MonitorRecord>, }, BackgroundTasksChanged { key: SessionSlot, tasks: Vec<BackgroundTask>, }, WorkChanged { key: SessionSlot, work: WorkState, git: GitWorkView, pr: Option<GitPrInfo>, closes: Vec<GitIssueRef>, }, TasksChanged { key: SessionSlot, tasks: Vec<Task>, }, CronSchedulesChanged { key: SessionSlot, crons: Vec<CronEntry>, }, ConnectorSubscriptionsChanged { key: SessionSlot, gotify: Vec<GotifySubscription>, slack: Vec<SlackSubscription>, }, SlashCommandsChanged { key: SessionSlot, commands: Vec<AvailableCommand>, }, SubagentsChanged { key: SessionSlot, subagents: Vec<AvailableAgent>, }, SubagentCardsChanged { key: SessionSlot, cards: Vec<SubagentCard>, }, FileIndexChanged { key: SessionSlot, index: Arc<FileIndex>, }, ServiceStatus { severity: ServiceSeverity, message: String, }, CatalogLoaded, CliVersionChanged, AccountsChanged { accounts: AccountPoolView, }, PluginsInventoryUpdated { cwd_raw: String, snapshot: PluginsInventorySnapshot, claude_path: PathBuf, }, PluginsInventoryRefreshFailed { cwd_raw: String, message: String, trigger: PluginUpdateTrigger, }, PluginsCliActionSucceeded { cwd_raw: String, result: PluginsCliActionSuccess, dispatch_id: Option<u64>, }, PluginsCliActionFailed { cwd_raw: String, message: String, dispatch_id: Option<u64>, }, PluginsUpdateRunProgress { cwd_raw: String, run: PluginUpdateRun, }, PluginsUpdateRunFinished { cwd_raw: String, run: PluginUpdateRun, snapshot: Option<PluginsInventorySnapshot>, claude_path: Option<PathBuf>, }, PluginsRollbackSucceeded { cwd_raw: String, plugin_id: String, scope: String, message: String, snapshot: PluginsInventorySnapshot, claude_path: PathBuf, }, PluginsRollbackFailed { cwd_raw: String, plugin_id: String, message: String, snapshot: Option<PluginsInventorySnapshot>, }, WorkerStatusChanged { project_key: ProjectKey, action: WorkerStatusAction, status: WorkerStatus, worktree: WorktreeDisposition, }, PeerEnvelopeAppended { key: SessionSlot, wrapped: WrappedPrompt, uuid: String, }, GotifyNotificationAppended { key: SessionSlot, notification: GotifyNotification, uuid: String, }, CronPromptAppended { key: SessionSlot, text: String, uuid: String, cron_id: String, description: Option<String>, }, SlackMessageAppended { key: SessionSlot, prose: String, uuid: String, }, SlackPostPending { key: SessionSlot, draft: SlackDraft, }, SlackDraftResolved { key: SessionSlot, id: Uuid, ending: SlackDraftEnding, }, BrowserHandOffPending { key: SessionSlot, handoff: HandOff, }, BrowserHandOffResolved { key: SessionSlot, id: Uuid, answer: HandOffAnswer, }, TerminalHandOffPending { key: SessionSlot, handoff: TerminalHandOff, }, TerminalHandOffResolved { key: SessionSlot, id: Uuid, answer: TerminalHandOffAnswer, }, TerminalChanged { key: SessionSlot, terminal: Option<TerminalSummary>, }, PromptQueued { key: SessionSlot, uuid: String, source: PromptSource, text: String, }, PromptLifecycle { key: SessionSlot, uuid: String, state: String, }, PromptCancelResolved { key: SessionSlot, uuid: String, cancelled: bool, }, ReviewActivityNotice { key: SessionSlot, branch: String, waiting: usize, message: String, }, DictateAvailability, DictateStarted { key: SessionSlot, floor_db: f32, generation: u64, initiator: Option<u64>, }, DictateLevel { key: SessionSlot, peak_db: f32, generation: u64, initiator: Option<u64>, }, DictateTranscribing { key: SessionSlot, generation: u64, initiator: Option<u64>, }, DictateProgress { key: SessionSlot, generation: u64, done: usize, total: Option<usize>, initiator: Option<u64>, }, DictateEnded { key: SessionSlot, outcome: DictateOutcome, generation: u64, surface: Option<String>, initiator: Option<u64>, }, FatalError { error: AppError, message: String, }, DictateModelsChanged { models: DictateModelsSnapshot, }, DocumentHandOffPending { key: SessionSlot, id: Uuid, path: String, reviewable: bool, }, DocumentHandOffResolved { key: SessionSlot, id: Uuid, ending: DocumentHandOffEnding, }, SettingsWritePending { key: SessionSlot, ask: SettingsWriteAsk, }, SettingsWriteResolved { key: SessionSlot, id: Uuid, ending: SettingsWriteEnding, }, VaultAskPending { key: SessionSlot, draft: VaultDraft, }, VaultAskResolved { key: SessionSlot, id: Uuid, ending: VaultAskEnding, }, BiometricEnrolmentsChanged { enrolments: Vec<BiometricEnrolment>, }, VaultRotated { refresh_token: String, }, VaultLockChanged { locked: bool, }, VoiceAudio { key: SessionSlot, seq: u32, sample_rate: u32, pcm: Vec<i16>, }, VoiceModeState { key: SessionSlot, listeners: u32, },
}
Expand description

Update envelope: forge-workspace -> a view.

Permission/Question variants do NOT carry response oneshots - responses flow back via Command::Respond*. The workspace stores the oneshot in DomainSession.pending_interactions when emitting these variants.

Clone is what lets the fan-out hand one emit to more than one subscriber, so every variant’s payload must stay cloneable.

Variants§

§

Spawning

Workspace is spawning a session (in response to Command::SpawnProject). A view creates a placeholder under key and shows the “Waking {display_name}…” message. The matching Connected lands soon after, under the same key.

Fields

§project_name: String
§display_name: String
§

Connected

Fields

§session_id: SessionId
§current_model: CurrentModel
§available_models: Vec<AvailableModel>
§history: Vec<Message>
§dropped: usize

Messages the read carried that history’s window left behind its front, which is the floor a page cursor below the window is measured against.

Carried because the window cannot say it. The read is windowed before it crosses - a resume’s whole transcript is gigabytes - so a consumer holding the window alone reads it as the conversation’s front, and a walk below it would stop there instead of crossing into the transcript. Additive on the wire, and zero for a read the window holds whole.

§compaction_count: u32

Compactions the resumed transcript records. Seeds the per-session count, which has no other durable source.

§

CallOutput

A call’s own output, asked for by Command::ReadCallOutput: the tail of the file the CLI streamed the call’s output to, or a named reason there is none.

Emitted by the transport from its held copy of the seat’s conversation, which carries the frame naming the call’s output_file.

Fields

§call_id: String
§output: CallOutput
§

SessionReplaced

The slot’s occupant changed under it - a /new, a /resume, a login or a logout. The slot keeps its bucket, in its place on screen; its contents reset, meaning the rendered conversation, the history, the per-session overrides and any waiter holding a tool call that is never coming back. session_id is the new occupant.

Fields

§session_id: SessionId
§current_model: CurrentModel
§available_models: Vec<AvailableModel>
§history: Vec<Message>
§dropped: usize

Messages the read carried that history’s window left behind its front: the same floor a Connected carries, for the same reason.

§compaction_count: u32

Compactions the resumed transcript records. Seeds the per-session count, which has no other durable source.

§

Handoff

The seat’s occupant was replaced by a handoff rather than by a person asking for one, and this is the record of it - emitted before any frame from the new occupant, so the seat learns the swap before the successor’s transcript starts. No view draws a row from it: the successor’s own procedure row carries the handoff.

Fields

§

MachineTurn

The machine turn running on this seat changed: a handoff beginning or ending, and None for a seat taking input.

A record read is not pushed. The record carries the same fact for a page that attaches mid-turn, but a page already open learns it here - and its composer stands down for exactly that span.

Fields

§

ConnectionFailed

Fields

§message: String
§fatal: bool
§

Releasing

The seat’s release has begun: its session is being taken down, and a view draws the seat as going to sleep until the roster lands it asleep or gone.

Announced at the START of the release, not when the handles drop. The teardown is what takes the seconds, so a viewer that hears only the end keeps the row reading as working through the whole gesture - and a close made from another view is heard by no one at all without this.

Fields

§

Notice

One line the core has for a view about key, which nothing else carries.

A command answered where both views dispatch has no other way to say anything: the CLI emits no frame for a command it never saw, and the line is the core’s own answer rather than a view’s opinion - what a command found, or why it refused.

Live only, and that is intended. The CLI writes no transcript row for a line it never produced, so a view draws this on arrival and a page that attaches afterwards has nothing to read it from. It is a statement about the moment a command ran, not a record of the conversation.

Fields

§text: String
§

SetModeFailed

The CLI refused (or failed) a set_permission_mode control request for key. message carries the underlying error text; the view rolls the optimistic mode chip back and surfaces it.

Fields

§message: String
§

SetModelFailed

The CLI refused (or failed) a set_model control request for key. message carries the underlying error text; the view rolls the optimistic model change back and surfaces it.

Fields

§model: String
§message: String
§

PermissionRequest

Permission prompt. No response_tx - a view replies via Command::RespondPermission { tool_id, outcome }.

Fields

§tool_id: String
§

QuestionRequest

AskUserQuestion prompt. Same shape; reply via Command::RespondQuestion { tool_id, outcome }.

Fields

§tool_id: String
§

PendingInteractionResolved

The interaction tool_id was answered, so every view holding the prompt can drop it. Answering leaves the pending set either way, and this is the only thing that says so on the stream: without it a second view keeps drawing a prompt that is already settled. A lone view never meets that, because it is the only one.

A question names its round as well as its call. A batch reuses one tool call id and advances question_index, and the next round’s request can land before this round’s resolution - so a clear keyed on the id alone dropped the ask that had just parked, and every round after the first lost its opening question (Ved’s live find; #1717). None on every interaction that is not a question, and on the frames of a core older than this field.

Fields

§tool_id: String
§question_index: Option<u64>

Absent from an older core’s frames, so the default carries that.

§answered_with: Option<String>

The words the answer carried, where it carried any: the box’s own notes, typed or dictated (#1360). None for a pick with no words, which is most of them.

§

McpOperationError

§

TurnComplete

Fields

§terminal_reason: Option<TerminalReason>
§

TurnCancelled

Fields

§

TurnError

Fields

§message: String
§class: Option<TurnErrorClass>

The failure’s class, where the producer that built the event could name one. None is “not classified here” rather than “not auth”: a producer that never classified and an auth failure are different facts, and a reader that folds them together holds a session on /login for an error that was never about login.

§terminal_reason: Option<TerminalReason>
§

ChatAppended

Fields

§source: Option<PromptSource>

Who dispatched the prompt this frame writes as a user turn: the same PromptSource the queue’s own row carries.

This is the arm a reader’s follow reads, because the words’ shape cannot say it: forge’s own machinery - an auto-continue, a worker kick, a board notice - forges prose as the reader’s own row on this frame, and arming for one carries a parked reader to the foot for words that are nobody’s (#2198). Only you is a person’s send.

None on every frame the CLI sent; the turns a delivery forges carry the delivery’s own kind, since their envelope row is not the reader’s either.

§

HookObservation

Fields

§tool_use_id: Option<String>
§permission_mode: Option<String>
§effort: Option<String>
§agent_id: Option<String>
§agent_type: Option<String>
§

ForgeAccountIdentity

Fields

§display_name: String
§

DictateOverrides

The full override set a session holds after a /dictate edit landed. Sent after every SetDictateOverride and ResetDictateOverrides so the dialog’s markers and its reset row read from this, not from a view-side copy.

Fields

§

ContextUsageSnapshot

Fields

§percentage: Option<u8>
§max_tokens: Option<u64>

Raw model context-window size in tokens (e.g. 1_000_000 for Opus 1M). None until the upstream probe reports it.

§

McpSnapshot

§

ProcessesChanged

The seat’s process tree moved, as the whole walk the core holds.

Pushed rather than read. The walk is a sysinfo refresh; the core runs it once a second for every seat a view is showing, and this carries the answer to whoever is drawing it. Emitted only when the tree’s own entries moved - a walk that found the same processes says nothing.

Fields

§

MonitorsChanged

The seat’s monitors moved, as the whole set the core holds.

Pushed rather than read. The set changes on discrete task frames - a Monitor call entering, a task stamping its id, a frame settling one, the drain that empties it - and never per output chunk, so the frame that moved it announces it and a frame that moved nothing says nothing.

Fields

§monitors: Vec<MonitorRecord>
§

BackgroundTasksChanged

The seat’s live task set moved, as the whole set.

Both halves move it: the CLI announces its background registry whole on each change, and a long foreground call enters on its task_started and leaves on its task_notification, a terminal task_updated, or the end of the turn that ran it. So this mirrors a task entering, leaving or being cleared by a dead connection.

§

WorkChanged

The seat’s working tree moved, as the row a view draws it.

Pushed rather than read. The three fields are the record’s own - the branch and count, the open PR on the pushed sha, and the issues it closes - so a client applies them to the fields it already narrows. A seat nobody is showing is not scanned, so this is only sent for a seat somebody holds.

Fields

§git: GitWorkView

The tree behind the row’s depth: the uncommitted files with their marks and counts, the branch’s chain ahead of its default, and which branch that is.

§

TasksChanged

The project’s task list moved, as the whole set the core holds.

Pushed rather than read. The tasks__* writes are the only movers and the section a view draws sits on the board’s project row - keyed by the project’s lead seat, which exists for every declared project - so the write announces the set rather than leaving the row to the next unrelated read.

Fields

§tasks: Vec<Task>
§

CronSchedulesChanged

The project’s schedules moved, as the whole set the core holds.

Pushed rather than read. Three doors move it - the cron__* writes, a fire that advances or removes an entry, and a worker’s teardown - and the section draws the countdown, so each announces the set it left. key is the project’s lead seat.

Fields

§

ConnectorSubscriptionsChanged

The project’s inbound connector subscriptions moved, as the two sets the core holds.

Pushed rather than read. The gotify__* / slack__* writes move them, and so do the doors no tool call reaches: a mention’s auto-subscribe, a watched conversation’s name healing on its first message, and a worker’s teardown taking its own with it. One update carries both connectors because they are one section of the board’s project row, and a reader that patches it needs the pair. key is the project’s lead seat.

§

SlashCommandsChanged

The / menu’s catalogue moved, as the whole list the core holds.

Pushed rather than read. The CLI advertises it on a turn’s init and re-sends it when a plugin changes it (commands_changed), so the frame that moved it announces it and a turn’s init repeating the same list says nothing.

Fields

§

SubagentsChanged

The agent-type catalogue moved, as the whole list the core holds.

Pushed rather than read. The CLI advertises it on a turn’s init, once per turn, so this is that one frame - and an init that repeats the list the last turn advertised says nothing.

Fields

§subagents: Vec<AvailableAgent>
§

SubagentCardsChanged

The session’s sub-agent instances moved, as the whole list the core folds from the frames it has seen.

Pushed rather than read. The join lives in forge_workspace::subagent_cards and folds a frame at a time, so a live session announces the list it now holds rather than re-walking its conversation per frame. A client draws the instances from this - the raw frames stay on the conversation for whoever folds something else - and a page attaching later reads the same list off the record.

Fields

§

FileIndexChanged

The tree’s file index moved, as the whole index the core holds.

Pushed rather than read, and throttled here rather than by the socket. The socket’s batch folds only consecutive token appends, so a burst of index frames would go out one per change: the walk runs at most once per poke while the watch says the tree is moving - so a build’s writes inside one poke become one walk - and once per INDEX_STALENESS when it is still. The frame goes out only when the index actually differs from the one last announced.

Fields

§

ServiceStatus

Fields

§message: String
§

CatalogLoaded

The background catalog scan finished and Workspace’s project catalog is populated. A view reads the roster itself, so nothing needs carrying: the event exists to wake the render loop so session counts appear when the scan lands rather than on the next unrelated frame.

§

CliVersionChanged

A claude version probe landed and moved what the views draw. The snapshot itself is not carried, so this is only the wake-up: a view re-reads through the surface’s cli_version verb.

§

AccountsChanged

The account pool moved: an account’s loading state, its last probe failure, its cached usage snapshot, or the gateway listener’s readiness.

The frame carries the pool’s drawn state, flattened so its fields are the ones HomeWire::accounts states - the same values, built by crate::Workspace::account_pool_view, so a client that folds the frame and a client that reads the snapshot cannot disagree (rule 25). That is what lets a usage move reach the badge without a home read.

It carries no seat because the pool belongs to none, which is also what routes it to a home subscriber and to nobody else.

Fields

§

PluginsInventoryUpdated

Fields

§cwd_raw: String
§claude_path: PathBuf
§

PluginsInventoryRefreshFailed

Fields

§cwd_raw: String
§message: String
§trigger: PluginUpdateTrigger

Whether the failed refresh served a boot auto-update run - app-scoped, so its failure bypasses the cwd gate.

§

PluginsCliActionSucceeded

Fields

§cwd_raw: String
§dispatch_id: Option<u64>

The dispatch this outcome answers, when the press that made it named one - None for an internal dispatch no press owns.

§

PluginsCliActionFailed

Fields

§cwd_raw: String
§message: String
§dispatch_id: Option<u64>

As on the succeeded frame above: the dispatch this failure answers, when the press that made it named one.

§

PluginsUpdateRunProgress

A section-level update run or check moved: one or more rows changed state. Carries the whole run so the pane replaces its copy wholesale.

Fields

§cwd_raw: String
§

PluginsUpdateRunFinished

The run (or check) is over. The record batch is persisted by the run task itself; this event is reporting only.

§

PluginsRollbackSucceeded

Fields

§cwd_raw: String
§plugin_id: String
§scope: String
§message: String
§claude_path: PathBuf
§

PluginsRollbackFailed

Fields

§cwd_raw: String
§plugin_id: String
§message: String
§snapshot: Option<PluginsInventorySnapshot>

The refreshed inventory when the rollback ran but did not verify, so the pane still reflects the real state.

§

WorkerStatusChanged

Workspace pushed a change to live_workers[project_key]. A view’s reducer updates the projects pane’s tree-children based on action. status is the snapshot at the moment of the change (relevant for Added and StatusChanged; ignored for Removed but carried for symmetry). worktree is what has become of the worker’s worktree, read on Removed events (after which the WorkerEntry is gone from live_workers, so a lookup-by-label would fail).

Fields

§project_key: ProjectKey
§

PeerEnvelopeAppended

A peer-coordination envelope arrived at key. Carries the typed WrappedPrompt so a view’s reducer can build the chat-side echo from real fields instead of having the workspace forge a Message::User carrying prose for a view to re-parse (audit I11). The recipient’s LLM still receives the prose via a separate Command::Prompt dispatch - that’s the CLI’s input channel and stays text-shaped.

Fields

§uuid: String

The id the delivered prompt was dispatched under, which the drawn row carries: a view holds the row while that prompt waits in the pile and draws it when it starts.

§

GotifyNotificationAppended

A matched Gotify notification arrived at key. Carries the typed GotifyNotification so a view’s reducer builds the chat-side echo from real fields (mirrors PeerEnvelopeAppended). The session’s LLM receives the same prose via a separate Command::Prompt - this update only drives the visible echo.

Fields

§notification: GotifyNotification
§uuid: String

The id the delivered prompt was dispatched under, which the drawn row carries - see PeerEnvelopeAppended.

§

CronPromptAppended

A due cron fired into key. Carries the fired prompt text so a view’s reducer builds the chat-side echo (mirrors GotifyNotificationAppended). The session’s LLM receives the same text via a separate Command::Prompt - this update only drives the visible echo.

Fields

§text: String
§uuid: String

The id the delivered prompt was dispatched under, which the drawn row carries - see PeerEnvelopeAppended.

§cron_id: String

The cron entry that fired, so a view can name the schedule the prompt came from - the entry is gone from the store by the time a run-once fire is drawn.

§description: Option<String>

The entry’s human summary; None when none was registered, and the row falls back to the prompt’s first line.

§

SlackMessageAppended

A matched Slack message arrived at key. Carries the prose rather than the typed message: the prose builder is pub(crate) to forge-workspace, so a typed message would force a view to rebuild the very format it parses. The session’s LLM receives the same prose via a separate Command::Prompt - this update only drives the visible echo (mirrors GotifyNotificationAppended).

Fields

§prose: String
§uuid: String

The id the delivered prompt was dispatched under, which the drawn row carries - see PeerEnvelopeAppended.

§

SlackPostPending

A composed Slack message is waiting for the user’s decision in the dock prompt. The authoring tool handler is blocked on a oneshot until Command::RespondSlackPost answers it, so nothing posts while this is outstanding.

Fields

§

SlackDraftResolved

A held Slack draft left the core’s registry: answered in some view, or its asking session gone. Each view keeps its own copy of the parked draft, so this is the only update that clears it - and ending is what a view that did not answer it says happened.

§

BrowserHandOffPending

A browser hand-off waits for the person at a client: the session asked them to act in a browser tab, and its tool handler is blocked on a oneshot until Command::RespondBrowserHandOff answers it.

No timeout rides this one. The ask dock’s own timelines say a held prompt sits for hours, and the session is meant to wait as long as it takes; the handler’s drop, not a clock, is what ends the wait.

Fields

§handoff: HandOff
§

BrowserHandOffResolved

A browser hand-off left the core’s registry: answered in some view, or its asking session gone. answer is the ending, the door that sent it and the connection that carried it - what a view that did not answer it reads, and what the log names.

Fields

§id: Uuid
§

TerminalHandOffPending

A terminal hand-off waits for the person at a client: the session asked them to type into the seat’s terminal, and its tool handler is blocked on a oneshot until Command::RespondTerminalHandOff answers it.

No timeout rides this one, and the agent is blind while it is parked: terminal__read and terminal__write are refused.

Fields

§

TerminalHandOffResolved

A terminal hand-off left the core’s registry: answered in some view, or its asking session gone. answer is the ending, the door that sent it and the connection that carried it.

§

TerminalChanged

A seat’s terminal opened, changed or closed, as the strip and the session record read it. None means the terminal is gone.

§

PromptQueued

A prompt entered the CLI’s queue: the row a view draws as waiting, with the words and the sender the lifecycle frames do not carry.

Emitted where the prompt is dispatched, keyed by the uuid it was sent under - so a view keys its own optimistic row to this one by id rather than by order or text.

Fields

§uuid: String
§text: String
§

PromptLifecycle

Where one prompt is in the CLI’s queue, as the CLI itself reports it: queued, started, completed and the terminal states (cancelled, discarded, refused). Keyed by the uuid the prompt was sent under, which is what lets a view key its queued row to its own send by id rather than by order or text.

state stays a free-form string so a state this build has not seen reaches a view rather than being dropped.

Fields

§uuid: String
§state: String
§

PromptCancelResolved

The CLI answered a cancel_async_message: cancelled: false means the prompt was already dequeued for execution, so a reader that asked to drop it has to say it is on its way instead.

Fields

§uuid: String
§cancelled: bool
§

ReviewActivityNotice

A worker’s review turn addressed review comments; key is the session that authored the review (the submit origin). A view drops message as a system line into that session’s chat so the reviewer sees the batched tally, and parks waiting - how many threads on branch now await a reviewer turn - as the persistent signal both the Inspector GIT badge and the NEEDS ATTENTION band read.

Fields

§branch: String
§waiting: usize
§message: String
§

DictateAvailability

Dictation models are loaded and the composer may offer to dictate. App-global (no key): the engine is process-wide and every session’s composer shares the availability; the event’s existence is the signal. Never emitted when [dictate] is disabled, so sessions that cannot dictate render nothing.

§

DictateStarted

A recording started for the composer at key. floor_db is the silence floor the level meter maps onto its zero glyph, so the bar and the NoAudio verdict agree by construction. generation identifies this take among the key’s takes: a resolver that arrives after a newer take started carries a stale one, and the composer resets on its own generation only.

initiator names the connection the take belongs to, as its dictate_stream carried it: every Dictate* update about a take goes to that connection alone, so no other subscriber draws its meter, its phases or its words. None is this process’s own take.

Fields

§floor_db: f32
§generation: u64
§initiator: Option<u64>
§

DictateLevel

One level reading for the recording at key: the peak over the window since the previous reading, in dBFS. Emitted on the meter clock, not the repaint clock.

A window with no signal reads as null on the wire, and null reads back as negative infinity. A peak that heard nothing is exactly zero, whose dBFS is negative infinity, and serde writes a non-finite float as null - so a reader that takes the field as an f32 cannot decode the message at all, which is the state this tolerance exists to close. Nothing about the value a view draws changes: the client narrows null itself, and this only lets a Rust reader do the same.

Fields

§peak_db: f32
§generation: u64

The take’s own, as SessionUpdate::DictateStarted announced it: a reading that arrives after a newer take started is the older one’s and belongs in no live meter.

§initiator: Option<u64>

The take’s own, as SessionUpdate::DictateStarted announced it.

§

DictateTranscribing

The take from key was submitted and a transcript is in flight.

Fields

§generation: u64

The take’s own, as SessionUpdate::DictateStarted announced it: a stale one must not move a newer take to transcribing while its microphone still records.

§initiator: Option<u64>

The take’s own, as SessionUpdate::DictateStarted announced it.

§

DictateProgress

A take from key has settled done segments of its transcription. total is None while the recording is still open, because a live take cannot know how many segments it will produce, and the final count once the take was stopped and its tail submitted. Single-segment takes report at stop only; a composer renders only what it wants to. generation is the take’s own, as handed out by SessionUpdate::DictateStarted.

Fields

§generation: u64
§done: usize
§total: Option<usize>
§initiator: Option<u64>

The take’s own, as SessionUpdate::DictateStarted announced it.

§

DictateEnded

A take from key is done: insert, notice or reset per DictateOutcome. generation is the take’s own, as handed out by SessionUpdate::DictateStarted.

Fields

§generation: u64
§surface: Option<String>

The surface whose own capture began the take, as Command::DictateStream carried it: the landed words are that surface’s to place, and no other’s. None for a take begun in process or by a client older than the field.

§initiator: Option<u64>

The take’s own - and for a refusal, the connection that was refused, so only it learns why. None is this process’s own.

§

FatalError

The core’s fatal: the app is going away. message is what a view draws on exit - AppError::user_message() - so a view that draws the line words it the same way without a second copy.

Fields

§error: AppError
§message: String
§

DictateModelsChanged

The catalogue check landed: the models page’s whole view, re-read. Carries no slot - the feed belongs to the machine, not a seat - and a session page ignores it. Sentinel rows the page draws (the check’s freshness, every candidate row, the per-model updates) are all here, so a subscriber that was already attached never has to ask again for what this frame just changed.

§

DocumentHandOffPending

A session handed the reader a document: the ask a client draws - open or not now - with the resolved path it opens at.

The call parks on this, like the browser hand-off: id names the parked call, and the reader’s answer releases it - NotNow here, or Approve / Feedback when the viewer’s finish files the reading. path is the resolved absolute path, the viewer’s stable address; reviewable is what the hand-off asked for - the ask’s own fact rather than the document’s, because a readable document offers its review either way.

Fields

§id: Uuid
§path: String
§reviewable: bool
§

DocumentHandOffResolved

A document hand-off left the core’s registry: finished in some view, declined, or its asking session gone. ending is what a view that did not answer it says happened.

§

SettingsWritePending

A configuration write waits for the reader’s approval in the dock: the session’s settings__set / settings__unset handler is blocked on a oneshot until Command::RespondSettingsWrite answers it, so nothing reaches forge.toml while this is outstanding.

§

SettingsWriteResolved

A held configuration write left the core’s registry: answered in some view, or its asking session gone. ending is what a view that did not answer it says happened.

§

VaultAskPending

A vault call waits for the reader’s approval in the dock: the family’s tool handler is blocked on a oneshot until Command::RespondVaultAsk answers it, so no operation runs in the vault while this is outstanding. needs_unlock on the draft is stamped from the live session as the card is built, so a sibling that unlocked first re-bases this one.

Fields

§

VaultAskResolved

A held vault call left the core’s registry: answered in some view, or its asking session gone. ending is what a view that did not answer it says happened; the tool result carries the operation’s own outcome.

§

BiometricEnrolmentsChanged

The device enrolments moved, as the whole set the core holds. Pushed rather than read: an enrol, a release’s stamp and a revoke each leave a set the settings page draws, and the card reads the same set - so a second client redraws without asking. No wrapped blob rides here; see forge_primitives::biometric::BiometricEnrolment.

Fields

§

VaultRotated

The shared vault session rotated its refresh token, so the copy an enrolment blob holds is spent. A client that holds the material from its last release rewrites its blob with this one (decision 15); one that cannot falls back to the password on its next start.

Slot-less: the session is process-wide, and only the client that owns the enrolment acts on it. The token is a secret on the socket - it never reaches a transcript or the live fold, and the manual Debug redacts it.

Fields

§refresh_token: String
§

VaultLockChanged

The shared vault session locked or unlocked outside a held card - the idle bound passed, a refresh or a decryption failed, or an unlock landed. Slot-less like the rotation: the session is process-wide, and the settings page’s vault card is what redraws.

Fields

§locked: bool
§

VoiceAudio

One rendered clip of the seat’s speech, mono 16-bit samples at sample_rate. Chunks arrive in seq order and every client with voice on for the seat plays them; a client with voice off receives them and stays silent.

Fields

§seq: u32
§sample_rate: u32
§pcm: Vec<i16>
§

VoiceModeState

The seat’s voice state: how many clients are listening, which is what the control draws and what a listener note is injected on.

Fields

§listeners: u32

Implementations§

Source§

impl SessionUpdate

Source

pub fn slot(&self) -> Option<&SessionSlot>

The SessionSlot this update routes to, or None for updates that target App-level state (ServiceStatus, catalog, plugin, fatal-error). Every identity-carrying variant names a slot, so nothing is synthesized here.

Trait Implementations§

Source§

impl Clone for SessionUpdate

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SessionUpdate

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for SessionUpdate

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for SessionUpdate

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Any for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

§

fn type_name(&self) -> &'static str

§

impl<T> AnySync for T
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send> ⓘ

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> DynClone for T
where T: Clone,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<S> FromSample<S> for S

§

fn from_sample_(s: S) -> S

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more