Skip to main content
OAO can copy each Daytona thread workspace to S3-compatible object storage. This is separate from Daytona’s own sandbox lifecycle: if Daytona no longer has the sandbox, OAO creates a replacement and restores the latest verified archive before the agent receives any sandbox tools. The same organization-shared storage connections also hold raw run attachments. Attachment objects use separate deterministic keys, bind to the selected provider at upload time, and are downloaded and integrity-checked before Daytona receives them. PostgreSQL stores their run manifest but never their bytes or extracted text. See Send files to an agent.

Add a storage provider

  1. Configure the same OAO_CREDENTIAL_ENCRYPTION_KEY for the API and runtime.
  2. Open Storage providers in the console.
  3. Select Add storage provider.
  4. Enter the region, bucket, optional HTTP(S) endpoint and object prefix, URL style, and write-only S3 credentials.
  5. Keep Make default selected, or make the connection the project default later.
AWS S3 works with an empty endpoint. Other compatible services can provide an endpoint and enable path-style URLs when required. Connection coordinates are immutable after creation so a thread’s existing archive remains addressable. Credentials can be rotated, and the project default can be changed.
OAO encrypts the S3 credential in PostgreSQL, but it does not add a second encryption layer to archive objects. Restrict bucket access and configure the storage provider’s server-side encryption, retention, versioning, and deletion policy for your requirements.

Backup lifecycle

The first successful backup binds a thread to the selected storage provider. Later default changes affect new threads; existing backed-up threads continue using their original provider. At each awaited agent-finish seam, OAO:
  1. asks Daytona for the sandbox workdir used by the agent and creates a gzip-compressed tar archive of that directory inside the sandbox, excluding Daytona’s .daytona/ runtime directory and the snapshot’s standard root shell/profile files (.bash_logout, .bashrc, .face, .face.icon, .profile, and .zshrc);
  2. lists the regular files in that workdir and uploads a bounded JSON manifest beside the archive in the same tenant-scoped object-storage prefix;
  3. uploads the archive to the thread’s deterministic tenant-scoped object key;
  4. stores the archive byte length, SHA-256 digest, latest owning run, timestamp, and generation in PostgreSQL; and
  5. overwrites the previous latest archive and manifest for that thread.
The file manifest contains relative paths, names, and byte sizes. It is bound to the archive’s byte length and SHA-256, and it stays in object storage. PostgreSQL does not store the workspace file list or any file contents. The manifest uses the same exclusions as the archive, so ignored Daytona runtime files do not appear in the session’s Files list. Restoration also applies these exclusions to older archives that may still contain those paths. The finish hook is at least once. Repeating it is safe because the object key is stable and PostgreSQL advances the recorded generation. A backup failure fails the run instead of reporting durable completion while the newest files are missing. The compressed archive limit is 512 MiB, and restoration rejects archives whose expanded tar stream exceeds 2 GiB. OAO deletes its temporary archive in the sandbox after upload or restore.

Restore lifecycle

When another run uses the thread, OAO first asks Daytona for the recorded sandbox. A running or restartable sandbox is reused normally. If the recorded sandbox is gone, OAO creates a replacement with the agent version’s selected snapshot, then:
  1. downloads the latest thread archive;
  2. verifies tenant metadata, byte length, and SHA-256 against PostgreSQL;
  3. validates the tar listing;
  4. asks the replacement sandbox for its workdir and extracts the archive there;
  5. records the restore timestamp before exposing tools to the model.
If a recorded object is missing, exceeds the limit, is corrupt, or cannot be extracted, restoration fails closed and the replacement sandbox is marked failed. OAO does not silently start the agent with an empty workspace. The session detail response exposes safe backup diagnostics under debug.workspaceBackups, including provider key, bucket, object key, byte length, generation, backup time, and last restore time. Credentials and archive contents are never returned. The console session panel reads the authoritative object-storage manifest and lists every regular file captured in the latest workspace archive, including files created indirectly by shell commands or APIs. Uploaded run attachments are also taken from their durable upload manifest and merged by their exact .oao/attachments/{runId}/{filename} path. An uploaded file can therefore show Uploaded + backed up, while a generated workspace file shows Backed up. Legacy archives without a sidecar manifest retain the earlier command-audit fallback until a later run writes a new backup. The panel never downloads or returns the archive itself. Each manifest-backed file has a download action that calls the authenticated session Files API. That API reads the verified archive from the bound persistent storage provider and never contacts Daytona.

Retrieve a workspace file

List the latest persisted files with GET /projects/{projectId}/sessions/{sessionId}/files, then download an exact relative path with GET /projects/{projectId}/sessions/{sessionId}/files/{path}. These routes use session:read, the same organization/project tenant checks as session detail, and the workspace owner’s storage binding. This also makes a coordinator’s shared workspace available through an authorized delegated child session. The list is empty until the first successful backup. Download verifies the manifest binding, archive length, archive SHA-256, entry type, and file size before returning bytes as a non-cacheable attachment. A missing or corrupt object fails closed. OAO does not query or revive the Daytona sandbox for this read path.

API example

See HTTP API for list, credential rotation, and default selection routes.

Current boundaries

  • One latest archive is retained per thread. Historical generations depend on bucket versioning; OAO does not expose a generation browser or rollback API.
  • Backup is automatic for Daytona-enabled threads when a default storage provider exists. There is no per-agent or per-session storage selector.
  • OAO does not test bucket connectivity during connection creation. The first backup is the first live write.
  • File downloads currently read and verify the latest compressed archive before extracting the requested entry; the API does not maintain one object per workspace file or support HTTP range requests.
  • Removing remote objects or changing bucket policy outside OAO can make a recorded backup unrestorable.