Expand description
forge-workspace - multi-session orchestrator and view-facing
facade.
Pools forge_agent::Agent instances behind a single
Workspace handle. One DomainSession per active session
holds workspace-internal routing metadata (AgentHandle slot,
claude-issued session_id, pending-interaction mailbox).
Operational state a view renders (lifecycle, cwd, turn state,
account info) stays on the view’s side of the wire; workspace is a
thin proxy that reacts to Commands in and emits SessionUpdates
out.
A per-session actor pumps events from AgentHandle::take_events(),
translates them into SessionUpdates, and routes Commands
back.
§Communication contract
The view ↔ workspace contract is one entry point in each direction:
- view → workspace:
Workspace::dispatchtakes aprotocol::Command. One enum, one entry point. - workspace → view:
Workspace::subscribe_mirrorandWorkspace::subscribe_answererreturn receivers forprotocol::SessionUpdate. Every caller gets a stream of its own, so a second view attaches beside the first, and a stream carries what is emitted after it subscribes. The socket’s own fold takes the mirror; each client takes the answering or mirror role it declared, throughViewSurface::subscribe_client. The role decides one thing: whether the core may park a prompt on that subscriber’s reply.
No callback hooks, and no state shared between a view and the core. A view
does not hold an
Arc<AgentHandle>: every outbound call goes through
Workspace::dispatch(Command); query-style refreshes
(refresh_context_usage, refresh_mcp_snapshot)
and direct accessors (settings_documents,
project_memory_path, config_dir_for) live as
inherent methods on Workspace. The handle stays on the
workspace’s DomainSession.
§Facade scope (intentionally thin)
The MVVM boundary between a view and forge-agent is enforced at
the dependency graph level: no view depends on forge-agent;
everything routes through forge-workspace. The
workspace exposes forge-agent’s submodules verbatim via
pass-through pub use (see the env, tooling, translate,
user_interaction and userdata modules below). Types reached
through them are defined in forge-agent - the workspace just
exposes them under the workspace name so a view can keep its dep
graph clean.
Re-exports§
pub use dictate::DictateAxes;pub use dictate::DictateBind;pub use dictate::DictateFailure;pub use dictate::DictateMode;pub use dictate::DictateModel;pub use dictate::DictateModelState;pub use dictate::DictateOverrideUpdate;pub use dictate::DictateOverrides;pub use dictate::DictateRole;pub use dictate::DictateSettings;pub use dictate::DictateSnapshot;pub use domain_session::ContextUsage;pub use domain_session::DomainSession;pub use domain_session::McpServers;pub use domain_session::TurnLiveness;pub use domain_session::liveness_of;pub use error::WorkspaceError;pub use handoff::ShippedSkill;pub use handoff::SkillInstall;pub use handoff::install_skill;pub use handoff::shipped_skills;pub use handoff::skill_dir;pub use handoff::skill_path;pub use protocol::Command;pub use protocol::DictateOutcome;pub use protocol::DispatchError;pub use protocol::NoticeSeverity;pub use protocol::PromptSource;pub use protocol::SessionUpdate;pub use target::SessionTarget;pub use tts::TtsSettings;pub use tts::TtsSnapshot;pub use tts::TtsView;pub use update_fanout::SeatUpdate;pub use vault::VaultState;pub use views::AccountGatewayView;pub use views::AccountLoadingRow;pub use views::AccountPoolView;pub use views::AccountUsageView;pub use views::ProjectView;pub use workspace::testing::set_seat_ring_cap;pub use workspace::BootWaveTarget;pub use workspace::LEAD_RESTART_NOTE;pub use workspace::PendingInteractionKind;pub use workspace::PricingFetch;pub use workspace::PricingFetcher;pub use workspace::SessionChipInfo;pub use workspace::SessionChipState;pub use workspace::SettingsSaveError;pub use workspace::Workspace;pub use mcp::cron::schedule::next_fire_after;pub use mcp::gotify::types::GotifyNotification;pub use mcp::peers::types::MessageId;pub use mcp::peers::types::WrappedKind;pub use mcp::peers::types::WrappedPrompt;pub use mcp::workers::types::LiveWorkerState;pub use mcp::workers::types::WorkerEntry;pub use config::BrowserSettings;pub use config::ConfigReload;pub use config::PluginSettings;pub use mcp::agents::build_server as build_agents_server;pub use mcp::peers::facade::MockWorkspaceFacade;pub use mcp::peers::types::PeerLiveness;pub use mcp::peers::types::PeerStatus;pub use mcp::workers::facade::CallerProject;pub use mcp::workers::facade::MockWorkerFacade;pub use mcp::workers::facade::WorkerFacade;
Modules§
- account_
cache 🔒 - Persistent forge state: the per-account usage cache.
- account_
loader 🔒 - Per-account boot-time loading task.
- bench
- Benching a model on this machine’s own material: which models a run can load, the config each one runs under, and the state and results the page reads.
- biometric 🔒
- The biometric proxy’s server half: each device’s enrolment, each purpose’s opaque blob, and revocation.
- board
- The board: one answer for every derived fact a reader of the task list needs.
- browser
- The browser the sessions drive: the port the tools ask through, and the hand-offs that park on the person.
- catalogue
- The dictation model catalogue: the feed’s check and the models page’s view.
- chase
- The chase sweep: the pass that makes the board drive instead of report.
- config 🔒
forge.tomlschema + loader.- conversation_
turns - Where a conversation’s turns open, in the shape the fold reads them.
- conversation_
window - The window a conversation is cut to when it is held or handed over.
- crons 🔒
- The cron cluster on
Workspace: the durable-cron store accessor and its mutation helpers, the asleep-slot prompt buffers, the fire router, the scheduler task, and the cross-crate seed helper. - dictate 🔒
- Dictation - the
[dictate]section inforge.toml, and the preflight pass that makes the models usable before forge starts. - documents
- The document hand-off’s parked ask: one document handed to the reader, held until their answer.
- domain_
session 🔒 - Workspace-side per-session state.
- env
- error 🔒
- Error types surfaced by
Workspace::newand friends. - file_
index - One working tree’s files, and the ranking the
@trigger reads a query against. - gotify 🔒
- The Gotify seam on
Workspace: the forge.toml[gotify]config accessor, subscription CRUD (durable rows in the redb store, ephemeral ones in memory), the subsystem start/stop lifecycle, and theGotifyHostport impl the forge-connectors pump drives. - handoff 🔒
- The handoff brief: forge’s own ground truth, and the handing-over session’s judgment.
- healing 🔒
- Auto-heal for dead seats: the supervisor that brings a durable lead or worker back when its subprocess closes while it should be up.
- hub
- The Hugging Face Hub calls the speaking model’s install makes: the repository’s current revision, its blobs with their LFS digests, and the download of one pinned file.
- idle_
sweep - The idle lead sweep: forge injects the board sweep when a project’s lead has nothing in flight.
- install
- Installing a model from the feed, and resolving which model each role runs: the doc’s own download link, a size-checked fetch into the models directory, the record of what arrived, and the config-key / runtime-pick / compiled-pin order an active model comes from.
- launch_
settings - The settings a session is spawned with.
- mcp 🔒
- In-process MCP server forge exposes to every spawned
claudesubprocess. - output_
tail - A command’s own output: the tail of the file the CLI streams it to.
- parked 🔒
- Payloads that arrived while their slot had no live session, addressed
by
(org, project, label)- the triple thesessionstable is keyed by. - plugins 🔒
- Plugin and marketplace actions over the command bus.
- prompt
- What a composer’s text means at forge’s own boundary.
- protocol
- Command + SessionUpdate channel envelopes between a view and forge-workspace. A view dispatches Commands; workspace per-session tasks emit SessionUpdates back through the workspace’s fan-out.
- provider_
probe 🔒 - Workspace-side routing of account probes through the forge-gateway backends, shared by the boot loader and the 60 s usage poller.
- review 🔒
- The review-conversation cluster on
Workspace: durable review-thread CRUD over the redb store, review submit / list / get, worker reply + resolve, the per-turn activity drain that notifies the reviewer, and the dead-branch sweep run off the startup path. - session_
task 🔒 - Per-session actor. Owns one
Arc<AgentHandle>’s event drain (AgentHandle::take_events) plus a per-sessionCommandreceiver. Translates eachAgentEventinto the matchingSessionUpdateenvelope and emits onto the workspace-wide fan-out, which hands one update to every subscriber. MutatesDomainSessioninline before each emit so workspace-side projections stay current. - settings
- The class catalogue and the effective-config document.
- settings_
ask 🔒 - The held configuration write.
- settings_
write 🔒 - The comment-preserving writer behind the settings editor.
- single_
instance 🔒 - Single-instance boot guard.
- slack 🔒
- The Slack seam on
Workspace: one client per configured workspace, the subscription records sessions create, and the boot verification that proves each token. - spawn 🔒
- App-level spawn command handlers. Called from
crate::Workspace::dispatchwhen an App-levelCommand::SpawnProjectarrives. Each handler resolves the id the session will run under, emitsSessionUpdate::Spawningunder it, and kicks off the agent spawn. The matchingConnectedarrives later under the same key. - store
- Machine-local embedded database (redb).
- subagent_
cards - The session’s sub-agent instances, folded as the frames arrive.
- systemone 🔒
- The System One decision tools’ workspace leg: the boot-time client construction, shared by the real boot and the testing stubs so both agree on trust handling.
- target 🔒
- Identifiers + the
SessionTargetenum used to address sessions. - tasks 🔒
- The task cluster on
Workspace: the durable task store accessor and its mutation helpers, a secondimplblock besidecrons.rsso every caller keeps its path. - terminal
- The per-seat terminals: the registry, the hand-off that parks on the person, and the idle clock.
- tooling
- translate
- tts
- The
[tts]section: what the speaking role runs, the Hugging Face install that supplies it, and the read the models page and the settings card draw. - update_
fanout 🔒 - Fan-out for the workspace’s
SessionUpdatestream. - user_
interaction - Pass-through for the agent’s typed tool-input parsers
(
AskUserQuestion,Monitor), which the server reads when folding a tool call into the block a view draws. - userdata
- vault 🔒
- The process-wide vault session and its audit.
- vault_
ask 🔒 - The held vault call.
- views 🔒
- Read-only views surfaced by
crate::Workspace::list_projects. - voice
- The per-seat voice service: listeners, the sentence queue, and synthesis.
- work
- The seat’s working tree: what a scan of it found, when that was, and the loop that keeps it fresh for the seats a view is showing.
- workspace 🔒
- The orchestrator.
Structs§
- Agent
Handle - Handle returned by
Agent::spawn. Owns the channels + a thin passthrough to the bridge’s direct-return accessors. - Background
Task - One of the seat’s live tasks, with the command its own card carried where forge has seen both.
- Project
Key - Project root path key - the canonicalised, sanitised string form
produced by
forge_agent::userdata::catalog::scan::project_key_for_directory. Equivalent to the directory names you see under<config_dir>/projects/. - Session
Launch Settings - Session
Slot - The
(org, project, label)triple naming one session.organdprojectare theforge.tomlnames - the same pair the redbsessionstable is keyed by - andlabelcarries the role:LEAD_LABELfor a project’s lead, the worker’s own label otherwise.
Enums§
- Context
- Destination conventions. Not a domain or vocabulary hint: it will not
protect technical terms, which are a
Stylingconcern. - Loading
State - Boot-time loading state for an account. The boot wave and the cron
spawn path wait for every account in the map to resolve to
ReadyorBailed; the selection walk skipsLoadingand keepsBailedas its last resort. A bailed account’susageisNoneby construction (the loader clears it on the transition). - Permission
Mode - Which permission flow the
claudebinary should use for tool invocations. Mirrors the upstream CLI’s six-variant set. - Runtime
Session State - Structure
- Whether the model may turn enumerable content into a bulleted list.
- Styling
- The register the transcript is rewritten into.
- Turn
Error Class - Coarse classification of a turn-level error message. The
classifier itself lives in forge-agent’s
translate::error_handling; this enum is the wire shape it produces. - Unusable
- Why an account is held out of the usable tier.
Which reason can apply is keyed on the account’s billing kind: only
a window-billed account can saturate, so on a spend row an unusable
account can only be probe-blocked. A snapshot whose source is not
the account backend’s is ignored here, so a cache surviving a
forge.tomlprovider edit cannot saturate the row it landed on. - Usage
Fetch Status - Classification of the latest usage-poll attempt outcome for an
account. Feeds
unusable_reason’s probe-blocked branch and the backoff schedule.
Constants§
- LEAD_
LABEL - The label reserved for a project’s own agent. A caller addresses it
as the
labelof anagents__send_messagetarget;agents__spawnrejects the label so no live worker can shadow the keyword. Reserved label for a project’s own agent, addressed as thelabelof anagents__send_messagetarget.agents__spawnrejects it so no live worker can shadow the keyword.
Functions§
- has_
a_ transcript_ row - Whether a transcript row carries a frame, which is what tells a copy’s numbering from the file’s when the frames the CLI never wrote are in it. Whether a transcript row carries this frame.
- session_
history - The messages a session’s transcript holds and the compactions it records. The same read the spawn performs, available for a session that is already running.
- session_
history_ main_ thread session_historyover the session’s own rows only: sub-agent sidecars are not opened or folded. The handoff brief takes this one, so it pays for neither the frames nor the parse. A page read does not: a dispatch row draws its sidecar frames (#1763).- transcript_
rows - The rows of a session’s transcript that sit strictly before
below, for a paging read that has walked below the window a conversation is kept in.