Files
qwen-code/docs/design/public-hosted-shell-admission.md
T

14 KiB

Public foreground Shell admission for Hosted Workspace Sessions

English | 简体中文

Status and problem

Implementation design for #13271, based on main bb66a52c. The Harness already supports persisted hosted-workspace-shell/1 and mandatory Shell approval. Public REST and WebShell creation still pin hosted-workspace-files/1; callers cannot opt into the foreground Shell path. This change exposes that existing path through deployment admission, without completing G3 Step 3 or Shell L4.

Scope and decisions

The deployment flag qwen.managed-agent.harness.workspace-shell-enabled (QWEN_MANAGED_AGENT_WORKSPACE_SHELL_ENABLED) defaults to false. Enabling it requires Workspace files and all their existing trusted local-process, Session-isolated Broker, mount, Session Store and Harness prerequisites. Approval mode must be default or auto-edit; yolo, missing, blank and unknown modes fail startup. This deployment mode is persisted for built-in qwen-code Workspace Sessions.

New Workspace-bound Sessions of the built-in qwen-code agent, including empty creation and creation with input, pin hosted-workspace-shell/1 when enabled, otherwise files/1. Unbound Sessions and existing files Sessions retain their behavior. No caller profile selector, metadata override, schema migration, public /2 search profile, background Shell, Monitor or new credential mechanism is added.

Stored AgentDefinition Sessions retain the profile and approval mode compiled from their pinned revision and the deployment allowlist. The Shell flag changes only the built-in agent's default profile selection; it does not override a stored definition. Every Shell Session still requires the Shell flag and valid asking approval for fresh execution. Harness load requests retain both the AgentDefinition identity and suppressChildAgents through child-Workspace, lifecycle and stopped-message copies.

The inherited Shell/1 declaration includes Monitor, but public creation does not configure capture bytes or the H3 publication lane. Existing admission rejects Monitor and background commands before approval or Broker execution. Real public tests exercise both refusals and assert zero side effects; the private H3 tool family is unchanged.

Public Shell create and load set suppressChildAgents. The Harness then does not attach the child-agent orchestrator, so the public tool list stays the file tools plus foreground run_shell_command and Monitor. Session messages share that orchestrator's write chain, so the same lane has no message funnel. A Shell lane that omits the flag keeps the child agent tool.

PR #13674 also separates the existing internal TeamLead rig with the reserved hosted-workspace-team-lead/1 profile and a trusted Java-only empty-creation entry. Public create and AgentDefinition cannot select this identity, including through idempotency replay. These public Shell rules still apply only to the unified Shell/1 profile. Authorized input, Actions and protocol-0 close on an internally created Session retain their private policy; opening public foreground Shell does not expose team tools. See the internal admission design for the persisted boundary and pending Linux/MySQL process acceptance.

Admission and persistence

Profile and approval mode are written in the existing creation transaction. They are server decisions, not inputs to the client request digest. Creation replay returns the original Session across a deployment flag change.

The V53 actor-role storage merged from main fbde5cf0 initializes the Session's creator and owner from the same authenticated actor key in that transaction, for Shell and files creation. Shell profile selection preserves both identity columns and the upstream role-based grants; this slice adds no handover or role-management operation.

With Shell disabled, existing Shell Sessions reject fresh Turns with 409 workspace_unavailable. Authorization still runs first. Both the service replay probe and the locked Store command probe precede the new Shell gate; original idempotency keys replay without accepting new work. The Store gate is authoritative. Disabling only the Shell flag preserves accepted work, approval decisions, cancellation and settlement while Workspace files remain enabled and persisted approval remains default or auto-edit. Files-off or invalid approval can refuse attachment; the shared Connector does not bypass those guards. Controlled W2 cwd changes do not execute Shell and retain their own files, actor, path and context-revision admission. The Shell flag is not a general Session freeze.

Persisted approval and recovery

Before returning a cached attachment or making a create/load/recovery request, the Connector validates that a persisted Shell profile has default or auto-edit approval mode. Invalid modes never silently become YOLO. Harness confirmation still must match the stored mode. Existing file YOLO behavior is unchanged. The unreleased Shell /2 identifier has been removed; public creation emits only the unified /1 profile.

Recovery reuses current G3 behavior. Requested approvals remain requested on a plain owner reattach. Durable allow/deny remains durable. Recovery may refuse at model_start or shell_in_flight with the existing recovery-blocked reason; no Shell is automatically replayed and no physical Workspace fence is cleared without verified recovery. This change does not promise full owner takeover.

Capabilities and lifecycle

Add optional public foreground_shell and WebShell foregroundShell. Files and unbound responses omit them, without a schema default. Stored Shell Sessions return true only when mandatory approval and deployment admission are valid; disabled Shell Sessions return false. This explicit false is necessary to distinguish an existing Shell Session from a files Session without exposing a caller-selectable profile. workspaceTurns expresses the OPERATOR submit and rename capability under the Session's creator-keyed execution facts. It can remain true when Shell admission is off and is not sufficient Turn admission. Shell fresh sending also requires foregroundShell=true. Disabling only Shell admission retains accepted cancellation under the prerequisites above; false caused by files-off or invalid approval does not guarantee cancellation. The actions capability likewise does not override attachment or response guards. Cancellation admits an OPERATOR caller on the Session's executable shape and remains independent of fresh-creation grants. Its dedicated cached attachment path performs the same persisted Shell approval validation. Older clients remain protected by the transactional admission gate.

The canonical Shell profile uses the existing lifecycle v2 path, advertised by default. An explicit QWEN_HOSTED_LIFECYCLE_V2_PROFILES value replaces the list; an empty value disables v2. Public close and active delete additionally require reliable original-Worker stop support, Session ownership and current read access. A completed close enables archive/unarchive; unarchive restores CLOSED. Foreground work and pending approvals return turn_active: cancel the original Turn and wait for settlement before requesting close again. Background Shell, Monitor and child Sessions use the existing drain and cascade. Missing execution, output or stop proof remains blocked for recovery. Turn cancellation and Session lifecycle retain their separate authorization and recovery guards. See the current lifecycle design.

Changes by component

Component Change
ManagedAgentProperties and application.yml Default-off flag and startup prerequisites
ManagedAgentStore / AgentStateStore Creation profile, fresh Turn gate, lifecycle exclusion, flag accessor
ManagedAgentService Persisted-profile capability projection and Shell lifecycle exclusion
QwenHostedHarnessConnector Mandatory approval checks before cache or RPC use
ApiModels / OpenAPI / generated WebShell API Additive optional Shell capability
Java WebShell provider Separate fresh send from accepted cancellation
Unit and Hosted public integration tests Admission, replay, approval, lifecycle and real-process coverage

Validation and acceptance

Configuration tests cover default-off, missing prerequisites and all approval modes. SQL-backed admission tests cover both surfaces, empty/initial creation, frozen metadata and profile, flag changes, replay, fresh rejection, ACLs and zero lifecycle operations. Empty and initial Shell creation in both approval modes, plus flag-off files creation, must persist the exact actor key in both creator and owner columns. Connector tests exercise create/load/cached/recovery validation with zero Harness calls for invalid modes and file YOLO controls. WebShell adapter tests prove disabled sending retains active cancellation. Both wire surfaces pin explicit false for flag-off Shell and omission for files and unbound Sessions. Lifecycle negatives use close-capable Runtime support and a completed files close receipt before switching the stored profile to Shell, so a missing Shell exclusion cannot pass through an unavailable Runtime fixture. Connector coverage includes cold and cached action responses with Shell disabled and rejects invalid persisted approval before any Harness call. Cancellation asserts its durable CANCELLING state and coordinator dispatch. A requested Action on a bound Shell/default Session with files enabled and Shell disabled must commit a matching decision receipt, complete the response operation and replay across surfaces after a lost answer with one delivery. This H2/MockMvc test uses a simulated Harness decision and does not prove real Shell execution or a deployment restart.

Defensive projection tests cover invalid non-null persisted approval and a manually constructed files-off store; SQL forbids null approval, and a validated deployment forbids Shell-on/files-off. Synthetic persisted Shell/2 rows exercise the existing exclusion predicate, without adding public Shell/2 creation. Lifecycle projections also retain the close-capable positive control with Shell enabled. Cached stream/rename reject invalid approval before Harness access; Shell/1 retains the non-executing cwd admission and replay contract.

The public integration fixture must fail immediately on one-shot Action response assertions. Receipt evidence waits for the attached Harness prompt to become inactive and recovery-blocked, and for all three receipt handlers to finish, before checking exact attempts and asynchronous failure channels. Public prefix checks retain their first failure and rethrow it. Allow stdout must reach the model, and Allow/Deny side effects are rechecked after replay. Teardown runs all cleanup steps even when the output probe fails, retaining the original failure.

Real Java/Broker/Session Store/Harness tests must prove public Shell Allow has one side effect, Deny has none, and lost response/retry does not execute twice. Cold attachment must preserve profile and approval. FG6f publisher/receipt failure tests require real worker and SQL evidence; macOS substitutes or H2 cannot certify Linux physical quiescence. Build, bundle, typecheck, focused package tests, Java packaging and Checkstyle, two clean self-audits and an independent review precede completion. Results live in .qwen/e2e-tests/public-hosted-shell-admission.md.

Historical validation at 9c5e2817, after merging main bb66a52c, passed 181 focused Java tests, 30 WebShell adapter tests, 341 CLI Harness/recovery tests and six real MySQL/Broker/Harness public integration cases. The receipt failure and committed-receipt/lost-reply cases each retain one dispatch and one side effect, with byte-identical receipt retries and verified capture resources. An independent flag-off/cold probe verifies Store/Service admission and the live Connector, including accepted approval/cancellation and a new Harness after natural writer lease expiry. This probe does not restart the complete Java deployment. Linux publisher/worker-kill physical gates remain unverified and keep rollout gated.

Rollout, limits and open questions

Keep the flag off until the deployment has evidence for #12904, #13010 and the public FG6f gates. This feature does not fix those independent issues, add full Shell lifecycle, or bypass a recovery refusal. Deploy all Session readers before creating Shell Sessions; an older binary must not reinterpret the stored profile as files. Upgrade the Harness before enabling the flag. An older Harness ignores suppressChildAgents and would advertise the child agent tool. Shell Action responses admit only the Session's recorded owner, not every Workspace operator, because the answer runs a command. The implementation choices for this slice are set; maintainer review of the public contract and rollout sequencing remains required. Missing physical test infrastructure is reported as an unverified gate, never a pass.

W1c offline Workspace migration remains files/1-only. A persisted Shell definition causes migration_profile_unsupported for its storage, so plan any W1c migration before creating Shell Sessions there. This slice does not widen the migration guard or add Shell migration support.