pub struct Workspace { /* private fields */ }Expand description
One workspace, resolved: the runtime it borrows, the model, and everything discovered on disk, ready to mint runs from.
Held by reference by every run it mints, so a host keeps one per repository
for as long as it wants to send prompts at it. Dropping it does not end the
runs already minted — a PreparedRun owns its session — but the MCP
connections go with it, and so does the runtime when this held the last
Arc.
Send and Sync: the runtime is shared through Arcs and creates
sessions from &self, so concurrent minting from one workspace needs no
lock of basis’s own.
Implementations§
Source§impl Workspace
impl Workspace
Sourcepub async fn open(path: impl Into<PathBuf>) -> Result<Self, RunError>
pub async fn open(path: impl Into<PathBuf>) -> Result<Self, RunError>
Opens path with basis’s defaults: a private runtime with the provider
auto-detected from the environment, the newest model it offers, and
every convention discovered where convention says to look.
builder is the same call with the knobs exposed —
including with_runtime, for the
host that opens many workspaces on one Runtime.
Sourcepub fn builder(path: impl Into<PathBuf>) -> WorkspaceBuilder
pub fn builder(path: impl Into<PathBuf>) -> WorkspaceBuilder
Configures a workspace before opening it.
Sourcepub fn prepare(&self, spec: impl Into<RunSpec>) -> Result<PreparedRun, RunError>
pub fn prepare(&self, spec: impl Into<RunSpec>) -> Result<PreparedRun, RunError>
Mints a run: a fresh conversation against this workspace.
Synchronous, and deliberately so — everything expensive already
happened. What this does is spawn a session on the existing runtime and
hand back the PreparedRun that drives it.
The spec’s prompt may be empty. Once a session outlives a turn, a
conversation with nothing said yet is a real state — it is what ACP’s
session/new opens — so the emptiness check belongs where a prompt is
actually sent, which is PreparedRun::execute and
PreparedRun::send. (The free prepare keeps
its own up-front check, because a one-shot caller that passed nothing
wants to hear about it before a session exists.)
Sourcepub fn resume(
&self,
agent_id: &str,
spec: impl Into<RunSpec>,
) -> Result<PreparedRun, RunError>
pub fn resume( &self, agent_id: &str, spec: impl Into<RunSpec>, ) -> Result<PreparedRun, RunError>
Picks up a conversation a previous process left behind.
agent_id is PreparedRun::agent_id, not the session id: mentra
persists agents, and a session is one process’s view of one. Resuming
replays the transcript from the store, so the first turn after this
already knows everything the last one did.
The workspace has to be the one the conversation belongs to. Nothing here checks that — mentra’s store is keyed by agent, not by path — so resuming an agent under a workspace it never ran in gives it that workspace’s context and tools alongside its own history.
Sourcepub fn fingerprint(&self) -> Snapshot
pub fn fingerprint(&self) -> Snapshot
A cheap stand-in for everything in this workspace a run could see.
The utility ADR-0014 kept when watch was deleted, on the type its
ledger row promised it to. The semantics are crate::fingerprint’s
verbatim: a digest over git ls-files plus HEAD, stat only, and
every uncertain answer resolving to changed rather than unchanged.
Fingerprints the workspace as it is now, not as it was when the workspace was opened — that is the whole point, since a caller’s loop asks it repeatedly against one long-lived workspace.
Blocking: it spawns git and stats files. An async caller belongs on a
blocking thread — tokio::task::spawn_blocking, or the equivalent.
Sourcepub fn path(&self) -> &Path
pub fn path(&self) -> &Path
The path this workspace was opened with, which is what its runs are scoped to.
Sourcepub fn root(&self) -> &Path
pub fn root(&self) -> &Path
The same directory as discovery resolved it, symlinks followed. What the
run header reports, and what fingerprint reads.
pub fn provider(&self) -> &str
Sourcepub fn context(&self) -> &WorkspaceContext
pub fn context(&self) -> &WorkspaceContext
The context documents discovered at open, weakest precedence first.
Sourcepub fn skills(&self) -> &[LoadedSkill]
pub fn skills(&self) -> &[LoadedSkill]
The skills this workspace registered on the runtime, after layering.
Only what this workspace registered. The registry itself is the
runtime’s and additive, so on a shared runtime a run may also be able
to load_skill what a sibling workspace registered — an accepted
consequence of sharing (see WorkspaceBuilder::open).
Sourcepub fn templates(&self) -> &[Template]
pub fn templates(&self) -> &[Template]
The prompt templates this workspace defines, after layering, name-ordered. Over ACP these become the client’s commands.
Sourcepub fn mcp_servers(&self) -> &[String]
pub fn mcp_servers(&self) -> &[String]
The MCP servers connected at open, by the names that took effect — which is the configured name unless another workspace on the shared runtime already held it, in which case it carries a deterministic suffix. Names only: nothing here echoes a command or a credential.
Sourcepub fn mentra_runtime(&self) -> &Runtime
pub fn mentra_runtime(&self) -> &Runtime
The mentra runtime the runs are minted on, for a host that wants mentra’s own surface — the task board, teams, the store — alongside basis’s.
The same bargain as PreparedRun::session: basis does not hide mentra,
and reaching past basis’s surface is a supported thing to do rather than
a workaround. Renamed from runtime() when ADR-0018 gave basis a
Runtime of its own, so the name says whose surface comes back.