Remote workspaces
Connect Caudra to a Workcell server when the repository and execution environment live on another host. Caudra keeps its terminal UI, model connections, and session state on the client. Workspace operations run at the selected endpoint.
Use compatible client and server builds. A matching version label alone does not establish compatibility. The pinned Workcell dependency includes reviewed-transfer contracts, with a hard break from older remote contracts. Incompatible persisted state fails without migration. See compatibility and release status for the exact pin and supported state formats.
This guide covers direct Workcell connections, where you provision the host and manage its process, credentials, TLS and storage. For optional e2b-libvirt lifecycle management, profiles, the template catalog and reviewed file transfers, use Managed Sandboxes. A failed remote connection never switches execution to the local checkout.
Direct Workcell connections are experimental and off by default. Turn them on with remote_workcell = true under [experimental] in the global caudra.toml, then restart Caudra. See Experimental features. The switch covers the --workcell-* selectors, caudra auth workcell, and caudra remote or /remote in a direct session. Managed sandboxes have their own switch and work without this one.
Prepare the server
Section titled “Prepare the server”Use a matching Workcell build with a working Python execution worker. A generic MCP endpoint or a read-only Workcell server is insufficient. Caudra requires the full first-party catalog with matching schemas, contract and result versions, annotations, and presentation metadata.
Live discovery must advertise these capabilities. Capability contracts use version v1, and declared limits must pass Caudra's bounds checks. Listed methods and guarantees must be enabled unless stated otherwise.
| Capability | Required methods and guarantees |
|---|---|
| Control plane | controlPlane = true with an empty controlPlaneMissing, or controlPlane = false with only changes missing, and executionEnvironment disclosure |
operations | exactPreparation, methods prepare, execute, status, cancel, release, and nonzero ledger and bounded progress-replay limits |
workspace | resolveDirectory, stat, list, readText, searchText |
workspaceMutation | prepared and rollbackOnFailure |
directExec | prepared and interactive = false |
watch | open, poll, close, and recursive |
projectAssets | discover and read |
scm | discover, status, log, diff, readSide, stage, unstage, discard, and preparedMutations |
changes | beginRecord, finishRecord, abandonRecord, openRecords, abandonOpenRecords, records, holders, hold, release, prepareRevert, prepareUnrevert, acknowledge, status, prepareCleanup, and a bounded maxPageSize. Optional for a direct host, required to attach a sandbox. See File revert |
reviewedTransfer | privateStaging, sealedPublication, conditionalDownload, singleRange, durableOutcomes, createsDirectories, and safeInventory |
Reviewed transfer also requires positive file, staging, I/O, lifetime, buffer and journal limits, with maxJournalStorageBytes >= maxJournalBytes. Binary reads use reviewed downloads. The old raw upload/download tools cannot substitute for these capabilities.
Missing capabilities fail startup, even if you disable the corresponding model tools. Keep execution-environment disclosure enabled. Do not pass --no-expose-execution-environment.
On the server, create private change record and transfer directories outside the exposed workspace. The paths below are examples to replace with your deployment paths. The token file must contain a bearer token of at least 32 bytes, supplied through your secret-management process.
install -d -m 700 /var/lib/workcell/snapshots /var/lib/workcell/transfersworkcell-mcp /srv/workspaces \ --transport http --http-bind loopback --port 3001 \ --http-token-file /etc/workcell/token \ --tool-group files --tool-group web --tool-group shell \ --tool-group python_execution --tool-group code_graph --tool-group transfer \ --allow-write --shell-policy /etc/workcell/shell-policy.toml \ --remote-server-id dev-server \ --remote-workspace-id dev-workspace \ --remote-workspace-generation generation-1 \ --remote-root-project-id dev-project \ --remote-principal-id developer \ --snapshot-root /var/lib/workcell/snapshots \ --transfer-root /var/lib/workcell/transfersThe --snapshot-root directory must already exist, be absolute, belong to the server process identity, have no symlink components, and be inaccessible to group and other users on Unix. It must not overlap the workspace. It holds one change record store per workspace, with its revert journals, separate from client session records. Without it the host keeps no change records, so its sessions have no file revert.
All five --remote-* identifiers and HTTP authentication are required for remote discovery. Keep the workspace generation stable across ordinary process restarts. Change it whenever you replace or reset the workspace. The server generates a separate process-instance identifier to detect lost volatile operation state.
--http-token-file and WORKCELL_MCP_HTTP_TOKEN are alternatives and cannot be combined. --http-bind container binds all interfaces and requires authentication. Workcell does not terminate TLS. Put an HTTPS reverse proxy in front of it for non-loopback access and configure --allowed-host for the authority forwarded by that proxy. The client endpoint is the /mcp URL. File transfer must reach the same authenticated server.
The shell policy file is operator-owned TOML. For example:
version = 1default = "deny"allow = ["git status*", "git diff*", "cargo test*"]deny = ["git push*"]Workcell's --yolo permits unmatched shell scopes while preserving explicit denies. It is separate from Caudra's --yolo. Use OS isolation and network policy for containment. Shell policy and file-root checks do not sandbox arbitrary programs.
Configure a profile
Section titled “Configure a profile”Store the same bearer token on the client:
caudra auth workcell set devUse the hidden prompt, or caudra auth workcell set dev --stdin with a secret source piped into stdin. Do not put the token in an endpoint URL or command argument. Credentials are stored under the client's persistent state directory in owner-only files, without OS-keyring encryption. caudra auth workcell list lists names and timestamps. caudra auth workcell delete dev removes the saved credential.
Create workcell.toml in the local user configuration directory, alongside the global caudra.toml. On Linux the default is ~/.config/caudra/workcell.toml. See platform configuration paths.
version = 1
[workcell.profiles.dev]endpoint = "https://workcell.example/mcp"cwd = "projects/app"credential_ref = "credential:dev"expected_server_id = "dev-server"expected_workspace_id = "dev-workspace"| Field | Type | Default | Description |
|---|---|---|---|
endpoint | string | required | The Workcell endpoint: HTTPS with any host, or HTTP on a numeric loopback address such as 127.0.0.1. Caudra refuses localhost, user information, a query, and a fragment |
cwd | string | required | The working directory, relative to the Workcell root, where . is the root itself. It cannot start with / or hold .. |
credential_ref | string | required | The saved bearer credential, as credential:NAME, which caudra auth workcell set NAME creates. A loopback profile needs one too |
expected_server_id | string | unset | An identity check: the connection fails unless the server reports this ID |
expected_workspace_id | string | unset | An identity check: the connection fails unless the workspace reports this ID |
caudra config example workcell prints every workcell.toml key with its default, all commented out. Reference configs shows the same text.
There is no [profiles.NAME] shorthand. Unknown fields and unsupported file versions are rejected. The profile file must be a regular, non-symlink file owned by the user and not writable by group or other users on Unix. chmod 600 ~/.config/caudra/workcell.toml satisfies the permission requirement.
Endpoints must use HTTPS, except HTTP on numeric loopback addresses such as 127.0.0.1 or [::1]. http://localhost is rejected. User information, query strings, and fragments are forbidden. Non-loopback endpoints require a saved credential:NAME reference. Raw tokens, env: references, and file references are not accepted selectors.
Tokens that live and die with a sandbox
Section titled “Tokens that live and die with a sandbox”A local sandbox manager that mints a fresh bearer token per sandbox has nothing worth saving. Set CAUDRA_WORKCELL_TOKEN in the environment of the Caudra process instead:
CAUDRA_WORKCELL_TOKEN="$token" caudra \ --workcell-endpoint http://127.0.0.1:49983/sandboxes/"$id"/mcp \ --workcell-cwd projects/app \ acpThe token is read once at startup and never written to the credential store. A saved --workcell-credential-ref takes precedence, so an inherited variable cannot override an explicit selector. Because selection already refuses a non-loopback endpoint without a saved reference, this variable reaches numeric loopback endpoints only.
Prefer a saved credential for anything long-lived. This path exists for tokens whose lifetime is shorter than the machine they authenticate to.
Direct numeric-loopback selection can omit the credential reference at the CLI parser level. The Workcell remote discovery extension still requires an authenticated server, so use a credential for a working connection. Profiles always require credential_ref, including loopback profiles.
Connect
Section titled “Connect”caudra --workcell-profile devcaudra --workcell-profile dev tools --namescaudra --workcell-profile dev skills --namescaudra --workcell-profile dev -p --prompt "run the focused tests"caudra --workcell-profile dev acpFor a one-off connection, use --workcell-endpoint, --workcell-cwd, and --workcell-credential-ref together. Do not combine direct selectors with --workcell-profile. See the CLI reference.
Remote selection applies to workspace tools and workspace UI operations. Explicitly configured client-local extensions remain local. It does not move provider authentication or model traffic to the Workcell host. Do not add the same endpoint as a generic MCP server alongside the selected Workcell backend.
Project context and trust
Section titled “Project context and trust”Caudra fetches remote project assets through a bounded, revision-checked manifest. It does not read a remote .caudra/caudra.toml, execute remote init.lua, source remote environment files, or load remote MCP configuration. The client checkout's project configuration is also excluded. Global client configuration and its environment file remain local inputs.
Supported remote assets are:
| Asset | Accepted paths and behavior |
|---|---|
| Instructions | AGENTS.md, AGENTS.local.md, CLAUDE.md, COPILOT.md, .cursorrules, .windsurfrules, .clinerules, CONVENTIONS.md, GEMINI.md, and CODING_AGENT.md, plus .github/copilot-instructions.md and .caudra/instructions. Directory scope determines applicability |
| Skills | One-level <name>/SKILL.md under .caudra/skills, .claude/skills, .opencode/skills, or .agents/skills |
| Commands | Immediate Markdown files under .caudra/commands, .claude/commands, or .opencode/commands. They are prompt templates, not client shell scripts |
| Workflows | .caudra/workflows/*.rhai, loaded only while experimental.workflows is on. Scripts require client approval before execution |
| Permissions | The exact .caudra/permissions.toml file. Restrictive rules apply immediately. Allows require review |
Skill and command directories use the order shown above, selecting the highest-priority remote tier. Project entries override same-named global entries. Instructions and skill text are model context, not permission grants.
Workflow approval and permission-allow trust bind to the remote authority, authenticated principal, project, resource identity, revision, and source digest. Editing the asset invalidates its prior approval. A local checkout's trust does not authorize an identically named remote file. Invalid or stale assets fail closed. Caudra approvals cannot override server policy.
An asset Caudra does not recognise and a path the host cannot read are both skipped, and the session warns you with their paths. .caudra/permissions.toml fails the session instead when it is unreadable or invalid. Context describes how workspace and client instruction files combine.
Only global client MCP configuration is loaded. Local stdio extensions require explicit trust and run with an isolated launch context, rather than inheriting the client checkout's cwd and environment. Treat global Lua plugins and approved local processes as trusted client code. Remote mode is not a sandbox for extensions.
Client-owned documents and state
Section titled “Client-owned documents and state”Conversation records, retained tool output, credentials, approval records, and the remote-operation journal stay on the client. Plans and memory notes also stay local, scoped to the remote workspace identity. They are not remote repository paths. Ctrl+O and /memory open them in the workbench, which saves them back to the same local store.
The plan tool reads or replaces this session's plan the same way locally and remotely. The host chooses the target, and tool arguments cannot select another document or session. Implement and Clear-and-Implement include validated plan content in the model-visible Build request, even when the selected profile has no file tools. Clear-and-Implement copies a remote plan into a document the new session owns.
Secure plan storage currently requires a Unix client. On Windows and other non-Unix clients, these storage operations return UnsupportedPlatform. A Unix Workcell server does not remove this client-side limitation.
Use the memory tool to list, read, write, and delete named notes, just as in a local workspace. Writes replace the complete note. Plans use plan read/write. Workbench saves check document revisions and reject stale edits. Remote file tools cannot edit client plans or notes. Profile restrictions still apply. Listing or reading notes and reading the plan need no approval, and other calls go through the normal permission checks.
Remote file contents and tool output can still enter model context and retained client output. Keeping the repository remote does not mean its content stays exclusively on the server.
Cwd and resume
Section titled “Cwd and resume”The profile or CLI cwd is relative to the Workcell root. Use . for that root and POSIX-style paths for subdirectories. These selectors reject absolute paths and .. components.
In the TUI, a standalone cd resolves a remote directory and refreshes its project context. It does not change the client's process directory. Remote shell commands use the selected immutable cwd handle. A directory change inside one shell invocation does not change later tool calls.
Navigation accepts cd .. and cd ../sibling relative to the current remote directory, as long as the result stays inside the exposed root. For example, from projects/app, cd ../library selects projects/library. Going above the root fails. A successful change persists the logical cursor for resume. SDK stream sessions accept the same standalone cd user messages.
Resume with the same remote selection:
caudra --workcell-profile dev --continuecaudra --workcell-profile dev --session SESSION_IDStored bindings include the endpoint origin, server ID, workspace ID, workspace generation, resource namespace, authenticated principal, and root project. They also retain cursor scope for cwd restoration and validation. A profile name or matching path alone is insufficient. Local-to-remote resume, a different authority, or a replaced workspace generation is rejected instead of silently rebinding history. Reconnect to the original identity or start a new session.
Resuming a direct remote session also needs experimental.remote_workcell, whether through --continue, --session, the session picker, the SDK, or ACP. Without it, resume fails with an error and never falls back to local execution. The session data stays intact.
An ordinary server restart preserves durable identity but changes the process instance. Caudra must refresh volatile handles and reconcile pending operations. Reusing a generation after a workspace reset defeats this distinction, so generation management is the operator's responsibility.
File revert
Section titled “File revert”A remote session records its file changes on the Workcell host, in the store behind --snapshot-root. The host keeps one store for each workspace identity, including its generation, and every client of that workspace shares it. Recording, preview, conflicts, unrevert, and recovery after an interrupted revert work as they do locally. What differs:
- A shell line or file tool that names an absolute path records the whole session directory, because the host does not reveal where the workspace lives.
- Protected paths such as Git metadata,
.env*files, and private keys are never recorded, wherever they are in the tree. - Record limits above what the host advertises are lowered to it.
- Deleting, trimming, or forgetting a session leaves its records on the host. They stay until newer records push them out of the store's size budget.
A host that does not offer changes, such as one started without --snapshot-root, still connects. Its tool calls run without records, Caudra says so once, and file revert is unavailable. A managed sandbox refuses to attach to a Workcell without change records.
Interrupted operations
Section titled “Interrupted operations”Caudra journals remote mutations before dispatch. When a reply is lost, it queries operation status rather than automatically repeating the mutation. Cancellation after dispatch is also reconciled through remote status. A timeout is not proof that nothing changed.
On connection and recovery, confirmed terminal outcomes can clear pending records. Forgotten server state, unavailable status, or an unconfirmed dispatched operation remains indeterminate.
The journal only records operations. A pending or indeterminate operation does not hold back later tool calls or workbench saves, in this Caudra process or in another one. Sandbox lifecycle actions, reviewed transfers, and attaching a session to a sandbox still refuse to start until the pending operations of the current workspace generation are reconciled or acknowledged.
Within one session, remote tool calls follow the local concurrency rules. Two writes to one file wait for each other and both apply, because the second is prepared only after the first has published. A write waiting at its permission prompt holds back later writes to the same file. Writes to different files run in parallel. Shell and Python calls take no file locks, so they never wait for a write and no write waits for them. Any remote call can still wait for a free operation slot when the host is at capacity.
File locks are shared within one session only, and a relative and an absolute path to one file take different locks. In those cases two writes can prepare against the same version of the file. Another session or a shell command can also change a file between preparation and publication, for example while the write waits at its permission prompt. The host then refuses to publish and leaves the file as it is. The model gets the answer a stale local edit gets: the file changed since it was last read and must be read again. Nothing was written, so the refusal leaves no pending record.
A patch that spans several files is the exception once one of its files is published. A refusal after that point leaves the patch partly applied, so it is reported as indeterminate and stays in the pending report until you acknowledge it.
An operation recorded against an earlier generation of the workspace is listed under its own heading. The host that ran it is gone, so it cannot be reconciled. Acknowledge it once you have checked its effects.
Use the recovery controller without asking the model to repeat the command:
- Preserve the client state directory and the server's
--snapshot-rootdirectory. - Run
/remote pendingto inspect the recorded operation IDs and states. - Run
/remote reconnectafter a connection loss, or/remote reconcileto query retained status on the current connection. - Inspect the remote files and process state before considering another mutation or acknowledgement.
Recovery commands
Section titled “Recovery commands”/remote and caudra remote are available when experimental.sandboxes or experimental.remote_workcell is on. Each checks the session's actual source, so a direct session needs remote_workcell and a sandbox session needs sandboxes.
| TUI command | Effect |
|---|---|
/remote or /remote status | Show connection state and a bounded list of pending operation IDs and states |
/remote pending | Show the same status and pending-operation report |
/remote reconnect | Rediscover the server, validate identity and catalog, then reconcile pending operations |
/remote reconcile | Query operation status and clear confirmed outcomes without resending mutations |
/remote acknowledge <operation-id> --accept-possible-effects | Clear that operation from the pending report after you have inspected it |
Acknowledgement is not cancellation, rollback, or proof of completion. The remote operation may already have changed files or may still be running. The exact --accept-possible-effects flag is required. Use the operation ID from the pending report, only after inspecting its possible effects. None of these commands retries a mutation.
The CLI uses the same controller without starting a model or loading project assets:
caudra --workcell-profile dev remote statuscaudra --workcell-profile dev remote pendingcaudra --workcell-profile dev remote reconnectcaudra --workcell-profile dev remote reconcilecaudra --workcell-profile dev remote acknowledge OPERATION_ID --accept-possible-effectsCLI recovery still needs a compatible, reachable server with the same identity. It is not an offline journal editor. Reconnect rejects identity or catalog changes rather than rebinding the session.
In SDK stream mode, send a text-only user message containing the same slash command:
{"type":"user","message":{"content":"/remote pending"}}Caudra handles it before model dispatch and emits a system message with subtype remote and a status string, or subtype remote_error and an error string. To acknowledge through the SDK, send /remote acknowledge OPERATION_ID --accept-possible-effects as the content. These are user-message commands, not SDK control_request subtypes. One-shot --print is not this controller. Use the remote CLI subcommand for scripts that only need recovery.