Skip to main content
Daytona is the only Run Environment for fleet-rlm. The canonical set is daytona. A Session holds its Root Sandbox and caller-owned interpreter under a Session-scoped lease and reuses them across sequential clean Turns. Grouped I/O still mounts a Workspace Volume Scope on an ephemeral Sandbox. A tainted or incompatible runtime rotates to a fresh Sandbox before the next Turn starts. This page is the deep cut on how that runtime is shaped. For the higher-level layering, see Architecture.

One process-owned AsyncDaytona

The process owns a single AsyncDaytona client. It owns provisioning, Sandbox lifecycle, filesystem calls, and Workspace operations, and every path through the runtime is native async. The only synchronous seam is DSPy’s CodeInterpreter.execute(). That seam receives an explicit, allowlisted async-to-sync view of a small set of interpreter methods, and it blocks only the DSPy worker thread. No other collaborator gets sync access to the client. You should treat AsyncDaytona as a process-lifetime resource. It is not per-Turn, per-Run, or per-Session.

Provisioning and snapshot policy

Every Sandbox boots from a base snapshot named by [defaults.daytona] snapshot. The current default is fleet-rlm-python313-v5. Recursive delegations bootstrap from the same snapshot, which lets them skip the per-run image pull. Build or refresh the snapshot with the CLI:
Verify the snapshot exists with make daytona-snapshot-check. Diagnostics for the full runtime path live under uv run fleet doctor daytona and are described below. Provisioning code lives in src/fleet_rlm/daytona/provisioning.py. The SDK boundary itself is in src/fleet_rlm/daytona/broker.py.

Volume policy

The runtime provisions exactly one Daytona Volume per configured deployment, and every Sandbox mounts it at a fixed path. The API URL and target are not configured through Fleet env vars. They come from the Daytona SDK defaults or the Daytona profile you have selected on the host. See Configuration for the full [defaults.daytona] reference.

Workspace Volume Scope

Workspace storage in src/fleet_rlm/workspace/storage.py opens a Workspace Volume Scope. Its only transport edge is the Daytona workspace agent client. Each grouped I/O operation is scoped to one ephemeral Sandbox, and that Sandbox is deleted before the context exits. Storage only provisions namespaces it owns. Everything else on the Volume is off-limits.
Bundled Skills stay host-owned. They are not copied into the Volume. Recursive child scopes are siblings of workspaces/<workspace-id>. A recursive child cannot reach the Root workspaces/<workspace-id> mount, even though both scopes share the same underlying Volume ID.

Session-scoped Root leases

A healthy Session holds one Root Sandbox and one caller-owned interpreter under a Session-scoped lease, keyed by the Workspace-plus-Session scope. Sequential clean Turns in that scope reuse the same interpreter, so ordinary Python globals such as variables, imports, and helper functions persist while the runtime stays healthy, compatible, and resident. Failure, cancellation, timeout, claim loss, commit failure, authorization failure, or uncertain settlement taints the resident runtime. Before the next Turn, Fleet closes the tainted runtime, acquires a fresh interpreter and a fresh Root Sandbox, confirms the old Sandbox is gone, and rehydrates only durable state: committed History, the Session Workspace, Workspace Memory, Attachments, and Artifacts. A healthy program-fingerprint change, for example a Skill-instruction or Tool-schema change, is a program rotation instead. Fleet builds a new Root RLM and program while handing off the existing caller-owned interpreter and Root Sandbox. Idle eviction and process or Sandbox replacement follow the same durable-only rule: arbitrary Python globals may be lost, durable state never is. If Daytona replaces the underlying Sandbox, the runtime remounts the Workspace Volume Scope, but Python globals are not preserved across that replacement.

Session pre-warm

POST /api/sessions schedules a best-effort background pre-warm: Fleet acquires a Root Sandbox, applies the canonical Volume layout, persists the Session binding, and releases the lease while the Sandbox stays running. When the first Turn arrives, it reuses the bound Sandbox instead of paying creation and layout cost, so the first-Turn sandbox path typically drops from around 8-10 seconds to around 2 seconds. The pre-warm is invisible to the API contract: the create response is unchanged, a Turn that arrives mid-pre-warm waits out the pre-warm claim within its deadline, a Turn that claims first makes the pre-warm yield, and a failed pre-warm leaves the first Turn acquiring normally. The following runtime settings bound lease behavior: The interpreter facade lives in src/fleet_rlm/daytona/interpreter.py. Session lifecycle around a lease lives in src/fleet_rlm/daytona/session_manager.py. Lease and rotation mechanics live in src/fleet_rlm/daytona/lifecycle.py and src/fleet_rlm/daytona/sandbox_lease.py.

Recursive child Sandboxes

Recursive delegations run through src/fleet_rlm/daytona/recursive_child_runtime.py under the daytona-recursive runtime label. Each child receives a fresh, dedicated Daytona Sandbox with ordinary Daytona network egress. The child mounts the same Volume ID at recursive/<workspace-id>/<run-id>/<call-index>. That is a private sibling scope. It cannot reach the Root workspaces/<workspace-id> mount. The child receives no Fleet Tools and no credentials. Cleanup is strict. Scope purge and Sandbox deletion both happen before the Root success can commit. A recursive child cannot leak state into the Root scope, and a Root Run cannot commit success while a child Sandbox is still alive. For the delegation contract itself, see Recursive RLM.

Attachments and Artifacts

Attachment bytes are written to the Workspace Volume Scope before their metadata, and they are staged for the Runs that reference them. That ordering means metadata never points at bytes that are not yet on disk. Artifact Candidates remain private Run outputs until two conditions hold: verified bytes have reached UUID-unique durable paths, and their metadata commits with the Turn. Failed metadata commits may leave GC-eligible orphan bytes on the Volume, but they never leave public rows.

Workspace files API

The /api/files* endpoints always resolve the process-local Workspace. Callers cannot select a Workspace, and they cannot address a Daytona Volume, mount, Sandbox, Attachment, Artifact, Session, or Run identifier through this API. The API offers bounded list and read pagination, append, in-place unique fragment edits, whole-file replacement, and strict delete. Writes, appends, edits, and deletes accept optional SHA-256 preconditions. The runtime never follows symlinks, holds a target lock across the operation, and revalidates the target inode across I/O Sandboxes. The workspace agent package src/fleet_rlm/daytona/workspace_agent/ services /api/files*, fronted by src/fleet_rlm/workspace/storage.py. Endpoint shapes are in HTTP API.

Workspace Memory

Workspace Memory is a single fixed file, MEMORIES.md, at memory/ under the mounted workspaces/<workspace-id> Volume subpath. The RLM Tools that operate on it are read_workspace_memory, remember, list_memories, search_memories, edit_memory, and forget. Each Turn also receives a bounded workspace_memory tail digest in session_context. The digest is capped at 4 KiB. It gives the model a small, always-fresh window over recent memory without forcing a Tool call. Memory Tool wiring lives in src/fleet_rlm/workspace/memory.py. For persistence guarantees around Memory across Sessions, see Sessions and persistence.

Volume tree endpoint

GET /api/volume/tree returns a bounded, read-only view of the relative paths inside the mounted Workspace Volume. It is a process-local logical view. It is not a general-purpose Sandbox filesystem browser, and it does not accept Sandbox or Volume identifiers.

Diagnostics

Validate the full runtime path with the doctor command:
The command validates the required settings, database connectivity and Alembic head, provider authentication, Volume visibility, scoped mounting, and interpreter execution. It creates exactly one uniquely labelled disposable Sandbox and deletes it in finally. It creates no Fleet domain rows. Output is limited to bounded categories and corrective actions. There is no fleet-rlm daytona-smoke command. fleet doctor daytona replaces it. There is also no POST /api/v1/runtime/tests/daytona endpoint.

Implementation pointers

See also

Architecture

Three layers of fleet-rlm and where the Daytona substrate sits.

Recursive RLM

How recursive children are scheduled and isolated.

Sessions and persistence

Session lifecycle, Workspace Memory continuity, and Run identifiers.

HTTP API

/api/files* and /api/volume/tree endpoint shapes.

Configuration

Full [defaults.daytona] and runtime.* settings reference.

CLI

fleet doctor daytona, fleet-rlm daytona-snapshot, and related commands.
Last modified on August 30, 2026