docs/design/web-shell-artifact-workspace-ownership.md
Status: implemented and verified
Issue: https://github.com/QwenLM/qwen-code/issues/8494
The Web Shell has one app-level DaemonWorkspaceProvider. Its default
workspace actions target the primary workspace. Session providers can attach to
secondary workspaces, but artifact surfaces currently retain or fall back to
the app-level actions. A file preview, download, review, nested subagent
artifact, or scheduled-task mutation can therefore reach the primary runtime
even though the producing session belongs to a secondary workspace.
The unsafe fallback also survives ownership changes: action objects are stored in right-panel tabs, so removing or distrusting a workspace does not invalidate an already-open tab.
The producing session owns every turn output. Its workspaceCwd, resolved by
the session connection, is the source of the owner claim. The current daemon
capabilities are the authority that accepts or rejects that claim.
A target is usable only when one of these cases holds:
capabilities.workspaceCwd.Unknown, duplicate, untrusted, removed, or identity-mismatched targets fail closed. They never fall back to the primary workspace.
Turn-output requests and right-panel tabs carry immutable owner identity
(workspaceCwd and the advertised workspaceId) instead of long-lived action
objects. ArtifactPanel resolves that identity against current capabilities on
every render. This makes workspace removal, trust loss, and runtime replacement
invalidate open tabs immediately.
The resolver returns a small artifact action surface only:
readWorkspaceFilereadFileBytesstatPrimary targets reuse the provider's primary actions. Trusted secondary
targets use client.workspaceByCwd(cwd) for file operations. Scheduled-task
operations still use the Web UI REST actions, but always receive the resolved
workspace id explicitly.
TurnOutputs derives the owner from its session workspaceCwd, uses the
scoped file actions for direct downloads, and stamps owner identity onto
review, artifact, and scheduled-task open requests.ChatPane and SubagentDetail preserve the request identity and add only the
producing session id. They no longer stamp root workspace actions onto the
request or artifact snapshot.App stores owner identity on each right-panel tab. Pane artifact snapshots
contain artifacts only; they no longer retain workspace clients.ArtifactPanel renders the existing workspace-unavailable state when the
owner cannot be resolved or no longer matches. It never substitutes
useWorkspaceActions() for a missing owner.workspaceId, and every list,
update, toggle, and delete request passes that id.Scoped action wrappers check that their captured owner is still current before starting an operation and again after each response. Effects and scheduled-task mutations also ignore results after unmount or owner replacement. A response started for one runtime cannot populate a tab after that runtime is removed or replaced.
workspaceId.