docs/design/2026-07-11-daemon-persistent-workspace-registration.md
Workspaces added from the Web Shell survive a qwen serve process restart
when the daemon is relaunched with the same primary workspace and QWEN_HOME.
Dynamic workspace registration is user-private daemon configuration, not project configuration and not disposable runtime output. Registrations are stored under:
${QWEN_HOME:-~/.qwen}/daemon/workspaces/<primary-scope-sha256>.json
The scope hash is the full SHA-256 of the canonical primary workspace path (lower-cased on Windows). The file repeats the primary path so a mismatched or corrupt scope is rejected rather than silently applied.
{
"schemaVersion": 1,
"primaryWorkspace": "/repo/main",
"workspaces": ["/repo/service-a"]
}
Only canonical secondary paths are stored. Trust, environment, workspace ids, sessions, and runtime errors are re-derived on every daemon start.
The production daemon reads the small registration file after resolving and
canonicalizing the primary workspace. Valid stored paths are merged after
explicit --workspace inputs. Explicit inputs are authoritative: a malformed
or unavailable explicit path remains a boot error, while an unavailable stored
path is skipped with a warning and retained on disk for a later restart.
Recovered paths enter the normal secondary-runtime construction loop before
WorkspaceRegistry and the Express/ACP surfaces are assembled. This keeps
capabilities, workspace-qualified ACP mounts, status aggregation, and the
default total-session limit consistent with the restored runtime set.
For process-local additions after app assembly, workspace-qualified ACP routes remain mounted whenever a registry exists and create a trusted secondary mount lazily on first use. This avoids a single-workspace startup snapshot making a later Web Shell registration unusable until restart.
POST /workspaces accepts persist: true. A successful persistent request is
not acknowledged until the registration-file update completes successfully.
Repeating a
persistent request for an already-active workspace promotes or confirms its
stored registration and succeeds idempotently. Existing callers that omit
persist keep the current process-local behavior.
GET /workspace-registrations exposes the desired stored set for management.
DELETE /workspace-registrations/:id forgets a stored registration; an active
runtime remains live until restart. The primary workspace can never be stored
or forgotten through this surface.
0600 and no symlink following.The additive persistent_workspace_registration capability advertises the new
contract. The SDK request option and persisted response field are additive.
runQwenServe owns automatic startup restoration. Direct createServeApp
embeds gain the persistence management routes only when a registration store
is explicitly supplied, and remain responsible for restoring their injected
workspace registry before app creation.
Hot removal remains separate: forgetting a registration affects the next restart but does not terminate sessions or dispose an active workspace bridge.