Skip to content

Workspaces and safe transactions

Workspace trust

A workspace is an executable input, not just a collection of source files. workspace-open evaluates MSBuild project logic, including repository-controlled projects and imports, before an agent can inspect every input. Later diagnostic and Code Action operations can load and execute project analyzers with the Host's operating system permissions. The Host does not sandbox workspace build logic or analyzers.

Open only a workspace whose source, project files, imported build logic, SDK configuration and analyzer dependencies are fully trusted. Inspect an untrusted repository outside Roslyn Workbench or in an operating-system sandbox first. The absence of a trust-confirmation request property is deliberate: a caller-provided confirmation would not isolate or validate executable repository content.

The connected MCP agent is also part of the local trust boundary. get-error-details may disclose local exception messages and Workspace context to that agent without a separate reporting-consent prompt. External submission remains a distinct sanitised and user-approved workflow; do not copy the local diagnostic record into a report or another service. See Error reporting and privacy.

Workspace lifecycle

After the caller has established that the workspace is fully trusted, workspace-open loads an absolute .sln, .slnx or .csproj into a workspace session. Use the returned workspace ID or alias to select it in later calls. When exactly one workspace is loaded, tools that accept an optional workspace selector may omit it.

Solutions may contain unsupported languages, projects without usable paths and non-SDK-style projects. The Host removes those projects from the loaded solution and returns WorkspaceProjectSkipped diagnostics. Loading fails when no supported SDK-style C# project remains. Unresolved analyser references are also removed and reported rather than preventing otherwise supported projects from loading.

By default, the workspace root is inferred from the loaded path. A caller may supply an existing absolute workspaceRoot that contains the loaded path to define the repository, coordination and transaction boundary. Every retained project must remain within that root.

workspace-open may also include msBuildProperties with the allowlisted global properties artifactsPath, configuration, platform, targetFramework and runtimeIdentifier. Omit the object when the project needs no caller-specific build configuration. Values apply only to that workspace's MSBuild evaluation and are retained across reloads; they do not change process environment variables. Unknown properties and empty values are rejected rather than passed through to MSBuild.

An artifactsPath must name an existing absolute directory because it is an MSBuild evaluation setting, not a filesystem permission. Project files must remain inside workspaceRoot. Source, additional and analyzer-config documents selected by the evaluated projects may reside outside it, including linked files, package-provided source and generated intermediates; those documents are transparently queryable but read-only. The Host certifies their loaded content against disk and polls their individual fingerprints for later changes without watching or trusting their containing trees. Source mutations remain strictly limited to workspaceRoot.

When the server runs under WSL and opens a workspace on a mounted Windows filesystem, workspace-open returns a WorkspaceOnWindowsFileSystemFromWsl warning. This layout is supported but can substantially reduce load and query performance. Prefer WSL-native storage or run the server directly on Windows.

workspace-status reports the selected workspace state, current transaction, reload requirement, diagnostics, other live Roslyn Workbench instances and the effective configured external error-reporting consent state. workspace-list provides a lightweight identity list and the current global transaction owner; it does not refresh cross-instance diagnostics.

If source inputs change outside the loaded session, the workspace becomes out of date or its active transaction becomes conflicted. Do not reuse old source locations, spans or symbol results against a different immutable solution snapshot. Echo the complete published snapshot object unchanged as expectedSnapshot, including its opaque snapshot ID; an epoch and transaction revision are not sufficient identity on their own. Reload or resolve the target again as directed by the structured error.

Cross-instance safety

Instance status is advisory. A durable inter-process lock serialises the final commit boundary, but it does not prevent two agents from independently staging transactions against the same workspace.

When workspace-open or workspace-status reports WorkspaceInUse, unavailable instance status or unreadable live-instance data:

  • treat that workspace as query-only;
  • use it only when necessary;
  • expect query results to become stale as the other instance changes files; and
  • coordinate mutation ownership before starting a transaction.

The Host does not infer coordination and does not reject transaction-start solely from advisory instance state.

Transaction workflow

Only one loaded workspace may own the server's active transaction slot.

  1. Check workspace-status, including cross-instance warnings.
  2. Call transaction-start for the selected workspace.
  3. Run mutation or Code Action tools. Successful operations stage a new revision; they do not write source files directly.
  4. Use transaction-preview and transaction-history to inspect, undo or redo staged revisions.
  5. Call transaction-commit to write the final staged source changes, or transaction-rollback to discard them.

Keep each transaction scoped to one coherent mutation or a tightly related set of changes. Start it when ready to mutate, preview the resulting scope, then commit or roll it back promptly. Do not use an open transaction to accumulate unrelated work. Run queries outside a transaction unless they need to inspect its staged solution, and treat broad solution-wide operations such as symbol rename as their own transaction. If preview reveals an unexpectedly large or unrelated change set, roll back and reassess it before committing. This keeps recovery work proportional to the current task because durable commit temporarily processes the original and intended content of every changed source file.

Queries run against the effective solution: the staged working solution while a transaction is active, otherwise the loaded baseline. Mutation, lifecycle and transaction operations require exclusive workspace access and may return WorkspaceBusy with a retry action instead of waiting in a server-side queue.

For Roslyn Code Fixes and refactorings, discover an action against the current revision and stage its opaque reference through the three-tool Code Action workflow. After a successful stage advances the revision, rediscover any subsequent action against that new current revision.

transaction-commit rechecks the source-file manifest and is the only public operation that writes staged source changes to disk. It does not compile the solution or modify project, props or targets files. Durable recovery records protect interrupted commits and are surfaced by server-status.

The non-cancellable filesystem application phases of transaction-commit and automatic startup recovery are short coordinated boundaries. While transaction-commit is in progress, the user and other development tools must not edit the source paths shown in its preview, switch branches, check out or reset paths, move directory trees, or replace directories with links. Edits completed before commit application remain subject to change detection and revalidation, but concurrent writes to a commit-owned target cannot be safely arbitrated during its final replacement. The transaction-commit response marks the end of commit application. Automatic recovery runs before MCP transport starts; avoid Workspace writes and structural repository operations until MCP initialisation marks the end of that recovery attempt, then call server-status with full detail and resolve any unfinished recovery entry before those operations proceed.

Source-file creation, deletion and same-directory rename do not update project membership. Default SDK compile globs normally reflect those changes after reload. For explicitly included, removed or excluded source paths, update the project file separately before relying on the reloaded project graph. Roslyn Workbench does not infer or persist that project-file change.