OpenClaw EnterpriseDOCSGitHub

Agent Workspace Files Flow

Overview

OCC privately stages authenticated creation inputs: AGENTS.md, SOUL.md, IDENTITY.md, and USER.md. Compute prepares storage; the execution provider initializes it before activation.

File operations authorize the exact active Agent through its Compute-resolved private Envoy endpoint.

Dedicated execution initializes the Harness workspace for Codex and native OpenClaw; see workspace and launcher boundaries.

See two-cluster transport for CP/DP routing.

Entry Points

Live access requires the Agent's private HTTPRoute and native gateway. Configure Envoy Gateway, trust, and network restrictions through deployment; the routing contract covers credentials, hostnames, and CAs.

Flow

graph TD
  subgraph Initial["Creation and first deployment"]
    S["Create Agent with initial files"] --> T["Authorize and stage exact-Agent input"]
    T --> U["Separate deploy request"]
    U --> V["Initialize through Compute or selected Sandbox"]
    V --> W{"Setup complete?"}
    W -->|no| X["Block execution; retain pending input"]
    W -->|yes| Y["Start runtime; activate Agent revision"]
    Y --> Z["Clear staged bytes; retain completion metadata"]
  end
  A["GET or PUT Agent workspace file"] --> B["OCC authenticates and validates request"]
  B --> C["Authorize exact Agent and resolve selected version"]
  C --> D["Compute derives private Agent URL"]
  D --> E["OCC reads service key and opens WSS"]
  E --> F{"Envoy authenticates OCC?"}
  F -->|no| G["503 dependency unavailable"]
  F -->|yes| H["Overwrite identity and real IP; route to Agent Service"]
  H --> I["Native gateway authorizes service identity"]
  I --> J["Native file get or set"]
  J --> K{"Result"}
  K -->|read| L["Return name and content"]
  K -->|write| M["Audit metadata and return name and size"]
  K -->|missing| N["404 NOT_FOUND"]
  K -->|unavailable| G
  K -->|write uncertain| O["Audit UNKNOWN_OUTCOME; never replay"]

Execution Trace

1. Creation validates and privately stages the inputs

apps/controller/src/console/agents/create.mts prefills four textareas from /console/workspace-defaults.mjs (packages/contracts/src/workspace-defaults.ts). It submits their values with WORKSPACE_DEFAULTS_ID. apps/controller/src/index.ts:createFastifyApp rejects a stale defaults identity; packages/contracts/src/workspace-setup.ts:normalizeInitialWorkspaceFiles rejects unknown names, invalid Unicode, NUL, and values above 16 KiB UTF-8. An absent or empty map follows ordinary startup without setup state; see the create body limit.

packages/occ/src/index.ts:createAgent checks Namespace-scoped Agent creation, exact Configuration read, and existing binding permissions. Its transaction creates a stopped Agent and, when keys were supplied, a private workspaceSetups record keyed by exact Namespace/Agent. No AgentRevision is created. Inputs do not enter the Agent, Configuration, Agent revision snapshot, public response, or metadata-only create audit. API strings are preserved; Console textareas use LF newlines.

packages/occ/src/index.ts:updateAgent keeps an omitted Configuration ID. Completed setup is rechecked when the resolved Configuration ID or execution mode changes. Saving Gateway managed mode alone keeps both. Pending setup is checked on each update.

2. Deployment initializes storage before execution

apps/controller/src/worker.ts reads private setup state into ComputeRevisionContext. A Driver without supportsWorkspaceSetup returns WORKSPACE_SETUP_UNSUPPORTED. The worker serializes Agent startup and passes workspaceSetup to Compute.

Bundled Drivers use apps/controller/src/drivers/compute/workspace-setup-runtime.ts:WORKSPACE_SETUP_RUNTIME. Kubernetes delivers an Agent-owned Secret to the workspace owner's init container (Gateway when embedded, Harness when dedicated); Docker uses a setup container and durable volumes; SSH uses the protected Agent directory. Provider-owned Harnesses require the Sandbox's validateWorkspaceSetup(harness, configuration): Compute delegates validation of the relocated workspace, or returns 409 before staging inputs. Preparation repeats this check.

OpenShell separately prepares native OpenClaw's private writable PVC subpaths, preserving retained entries. Ownership/mode checks, UID-fenced deletion and writer termination precede Sandbox creation. This permission setup carries no documents; see OpenShell preparation.

apps/controller/src/drivers/compute/kubernetes/index.ts:harnessRequirementsFromDeployment hands Sandbox the setup identity and exact Secret reference. After Sandbox readiness, apps/controller/src/drivers/sandbox/openshell.ts:initializeWorkspace verifies the Secret's Namespace, Agent and setup identity, then calls authenticated ExecSandbox with a fixed initializer and JSON stdin. Contents stay out of provider configuration, arguments and environment; remote output is discarded. The launcher waits for completion. A workspace flock serializes attempts after lost acknowledgments. The verifier uses OPENCLAW_WORKSPACE_DIR after relocation.

The runner validates setup identity and workspace paths, rejecting symlinks and conflicting contents. First setup requires the installed OpenClaw version and template digest to match WORKSPACE_DEFAULTS_VERSION and WORKSPACE_DEFAULTS_ID in packages/contracts/src/workspace-defaults.ts. Native setup initializes workspace/Git without starting Gateway. Kubernetes init containers use Gateway resource budgets. Supplied files, including empty strings, atomically replace only absent, stock, or already-submitted content. The runner reruns setup for BOOTSTRAP.md, verifies results, and atomically writes .oce-workspace-setup.json.

Matching markers skip replay; incomplete writes revalidate. After recorded completion, missing/mismatched markers block startup, preserving edits. Kubernetes initializer logs can include allowlisted codes such as EROFS. Temporary-directory cleanup preserves an earlier setup error.

apps/controller/src/drivers/compute/kubernetes/index.ts:safeRuntimeFailureObservation reports exit 2 as WORKSPACE_SETUP_REFUSED; other failures retry (WORKSPACE_SETUP_RETRYING). OpenShell raises SandboxWorkspaceSetupRefusedError on refusal, reporting RPC status or exit/timeout only. Docker retries failures without interrupting setup, staying unready. checkedAt records termination/observation time.

3. Activation clears staged contents and keeps completion metadata

apps/controller/src/worker.ts completes setup in the activation-completion transaction only after checking the selected Agent revision ID and work claim. workspaceSetups.complete removes document bytes and retains identity and completion metadata. Drivers remove or replace private delivery bytes with metadata.

Failed or never-deployed Agents retain pending inputs. Agent deletion removes the setup record through packages/occ/src/index.ts:deleteAgent; Driver cleanup owns runtime storage. No public endpoint reads or updates setup, and live edits after activation do not update it.

4. Composition configures private access

apps/controller/src/api-startup.ts:startApi validates the optional absolute OCC_GATEWAY_API_KEY_PATH before opening the database. Production and PostgreSQL development composition bind the selected Compute Driver to createWorkspaceFilesAccess. The worker uses that key for node enrollment.

API and worker Pods wait for the root Secret and load only public CA trust through NODE_EXTRA_CA_CERTS at startup, never the CA signing key; the TLS lifecycle covers the automatic CA and explicit issuers.

Kubernetes derives endpoints from admitted IDs and Installation routing; Drivers without endpoint support cannot serve workspace files.

5. OCC admits one exact-Agent file operation

apps/controller/src/index.ts:createFastifyApp requires a valid user session or scoped service API key. Native Agent credentials cannot invoke this administration surface. GET needs Agent read; PUT needs Agent operate and, for session callers, passes the browser CSRF boundary. OCC resolves the selected AgentRevision before Compute endpoint resolution. After that grant, an Agent with no running version (stopped, never deployed, or still activating) gets 409 RESOURCE_CONFLICT naming the Agent and the next step.

Names, the PUT body, and content and body limits follow the live file contract. The deadline and disconnect signal cover admission and native access.

6. Compute resolves a route and OCC loads the current key

apps/controller/src/composition/workspace-files.ts:createWorkspaceFilesAccess uses ComputeDriver.getGatewayEndpoint(revision) to resolve wss://<hostname>[:<endpointPort>]/namespaces/<namespaceId>/agents/<agentId>. Hostname defaults to Helm's Service DNS, port to 443; resolution does not prove readiness.

kubernetes/index.ts:reconcileGatewayRoute provisions operator routing plus an exact /node HTTPRoute and SecurityPolicy for dedicated runtimes. Only operator routes allow admin UI subpaths; both strip authorization and cookies. The node endpoint contract owns route ownership across preparation, activation, stop and retirement.

prepareWorkspaceNode calls gateway/node-enrollment-client.ts:createGatewayNodeEnrollment after Gateway readiness. Each Harness kind uses an Agent-owned setup/identity Secret. confirmWorkspaceNodeSetup retains setupReceiptDeviceId before node.describe. packages/gateway-client/src/client.ts saves and reads back the token, reconnecting token-only. src/gateway/server-methods/nodes.read.ts reports deviceTokenAuthenticated from src/gateway/node-registry.ts, bound to the current session and pairing generation. Promotion requires true; live approval invalidates proof and forces reauthentication.

After OCC retains a receipt, expired status cannot trigger fresh credentials. First reconciliation after Gateway's 20-minute retention can renew setup without recovering its receipt (readiness TODO). Harness storage owns recovery. Native provisioning requires Sandbox; expired unpaired setup awaits Gateway.

The chart supplies worker credentials/public trust; Compute installs Envoy access. Memory uses node duplex and native file workers; index/embedding configuration stays on Gateway. Skills uses remote discovery, reads and policy-checked dependency installation. Hosts initialize their own image assets. Gateway Skill sources stay local; native turns can receive temporary resource copies. See the ownership table. Remote channel menus remain deferred to #241.

Only Harness mounts the dedicated workspace, generated images and Codex rollouts. Rollouts retain history without guaranteeing restart recovery; see restart limits. The rest of CODEX_HOME stays Pod-local. External OAuth uses ephemeral placeholders and metadata; the token service owns refresh. Codex's remote-media reader retrieves reply artifacts before cleanup. Embedded storage is unchanged. KubernetesComputeDriver.verifyPersistentVolumeClaim rejects RWX claims without mutating them. The worker stops predecessors and suppresses their maintenance before dedicated preparation. The storage contract owns RWO, downtime and recovery limits. These contracts require matching runtime images; local checks do not prove deployed acceptance.

The API reads the mounted key per operation, so new connections pick up Secret rotation without a restart. Missing routing or keys, invalid keys, expired deadlines, and unavailable targets fail closed. No URL or credential comes from the caller.

7. Envoy authenticates and routes the native connection

apps/controller/src/gateway/workspace-files-client.ts:requestNativeWorkspaceFile opens WSS with only the service key in x-api-key. The client verifies the server hostname and CA; there is no leaf pin, device enrollment, native token, or client-certificate option. It connects as a backend operator with deviceIdentity: null and no self-asserted scopes.

The Gateway-level Envoy SecurityPolicy verifies and strips the key. The exact Agent HTTPRoute overwrites x-occ-identity, removes forwarded and native-scope headers, and sets X-Real-IP to Envoy's direct downstream socket address. It rewrites the upgrade path to / for the same-namespace Agent gateway Service. Namespace attachment labels, route ownership checks, and restricted Kubernetes RBAC protect this mapping.

Kubernetes Compute renders native trust from Installation network.gatewayTrustedProxyCidrs; conflicting tenant trust settings fail deployment. allowRealIpFallback accepts the genuine nonloopback OCC connection address even within a shared Pod CIDR. NetworkPolicy admits only Envoy to the native gateway; the CIDR is not an independent authentication boundary. Native hello grants operator.admin; reads also accept operator.read.

8. Native file access limits reads to 16 KiB

apps/controller/src/gateway/workspace-files-client.ts:requestNativeWorkspaceFile uses Hello's sessionDefaults.defaultAgentId when embedded OpenClaw composition opts in and native ownership is sole with selectionRequired: false. Other rosters retain the explicit main target; other callers retain their targets. Dedicated Codex binds only main to its workspace node, so deployment refuses a roster without it (requireDedicatedMainAgentDefault). No roster RPC or additional scope is required. The client invokes agents.files.get or agents.files.set. Reads enforce the response content limit and return { name, content }; writes return { name, size }. There is no list, delete, compare-and-swap, generic RPC, chat bridge, or PostgreSQL file copy.

Certificate renewal under the same CA reaches new WSS connections without an OCC restart. Root-CA replacement follows the trust rotation requirements.

Writes audit only the Agent resource, authorization action, outcome, reason when present, and file name. If a dispatched write has an unknown outcome, OCC returns 503 UNKNOWN_OUTCOME, attempts the corresponding audit, and never replays it. Cleanup closes the native client.

Debugging and Verification

Search documentation