Skip to content

Archive a sandbox to its filesystem, and unarchive it back - #228

Merged
drappier-charles merged 5 commits into
mainfrom
cdrappier/devin/sandbox-archive-lifecycle
Aug 26, 2026
Merged

Archive a sandbox to its filesystem, and unarchive it back#228
drappier-charles merged 5 commits into
mainfrom
cdrappier/devin/sandbox-archive-lifecycle

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

The control plane can now archive a sandbox — export the filesystem changes it made over its image, then release its compute — and unarchive it later. This exposes both as sandbox methods, in the async and the sync SDK, on the instance and on the class:

await sandbox.archive()                       # returns once ARCHIVED
await sandbox.unarchive()                     # returns once DEPLOYED again
await sandbox.archive(wait=False)             # returns as soon as the export is launched
await SandboxInstance.unarchive("my-sandbox") # like delete/fork, by name

Both the export and the restore run in the background (minutes for a few gigabytes), so wait=True is the default and polls the sandbox record: archive until ARCHIVED, unarchive until DEPLOYED, both with a configurable timeout (30 min) and interval (2 s). A sandbox that leaves the states the operation goes through — say a failed export gives it back as DEPLOYED/FAILED — raises instead of waiting out the timeout.

Both forms share one descriptor, so the class-level and the instance form cannot drift:

SandboxInstance.archive = _AsyncSandboxCallDescriptor(
    _archive_sandbox_by_name, "archive", target="ARCHIVED", pending={"DEPLOYED", "ARCHIVING"}, ...
)

The instance form writes the refreshed record back into the shared SandboxConfiguration, so sandbox.fs/sandbox.process and a forced session URL keep working across the call.

Generated client: archive_sandbox/unarchive_sandbox, the SandboxArchive/SandboxArchiveRestore models, and the ARCHIVING/ARCHIVED/UNARCHIVING statuses.

The integration test is gated behind RUN_SLOW_TESTS: an archive and its restore take minutes each way, well past the one-minute budget.

Link to Devin session: https://app.devin.ai/sessions/43a2b5615507438a8abb55723c9298e3
Requested by: @drappier-charles


Note

Medium Risk
Introduces long-running lifecycle operations with status polling; incorrect wait logic could mislead callers about when the filesystem is safe to write, though changes follow existing sandbox API patterns and are well covered by unit tests.

Overview
Adds sandbox archive/unarchive to the Python SDK so callers can export writable filesystem state to the archive store (releasing compute) and later restore it onto a new instance with processes restarted from saved configuration—not live memory.

Generated client: new POST /sandboxes/{name}/archive and unarchive helpers (sync/async), Sandbox.archive metadata models (SandboxArchive, restore progress), and deployment statuses ARCHIVING, ARCHIVED, and UNARCHIVING.

High-level API: SandboxInstance and SyncSandboxInstance expose archive() and unarchive() on both the class (by name, like delete) and the instance. By default they poll until ARCHIVED or DEPLOYED (30 min timeout, 2 s interval), with wait=False to return immediately; failed or unexpected status transitions raise SandboxAPIError instead of hanging. Instance calls refresh the embedded sandbox record so fs/process keep working.

Tests: mocked coverage for wait/timeout/failure paths plus opt-in slow integration tests (RUN_SLOW_TESTS) for filesystem retention and preview URL stability across archive/restore.

Reviewed by Cursor Bugbot for commit 8218851. Bugbot is set up for automated code reviews on this repo. Configure here.

drappier-charles and others added 2 commits August 26, 2026 00:18
sandbox.archive() keeps the filesystem changes made over the image and releases the compute; unarchive() writes them back over a new instance. Both wait for the background export/restore to finish unless wait=False, and both work as SandboxInstance.archive("name") like fork does.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

DEPLOYED sat in the archiving statuses and ARCHIVED in the restoring
ones, the very statuses a failed export or restore reverts to, so a
failure looked like progress and polled for the full 30 minutes. The
entry status is now tolerated only while the operation starts.

Also exercises the whole lifecycle against a real sandbox: an app behind
a preview, archived, given back, the same preview URL serving again, and
the sandbox deleted.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@drappier-charles
drappier-charles marked this pull request as ready for review August 26, 2026 00:59
…rst wait

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment thread src/blaxel/core/sandbox/default/sandbox.py Outdated
Comment thread src/blaxel/core/sandbox/default/sandbox.py Outdated
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@drappier-charles
drappier-charles merged commit e5118d5 into main Aug 26, 2026
18 checks passed
@drappier-charles
drappier-charles deleted the cdrappier/devin/sandbox-archive-lifecycle branch August 26, 2026 01:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant