Skip to content

feat: snapshots#1111

Open
dobrac wants to merge 8 commits intomainfrom
feat/snapshots
Open

feat: snapshots#1111
dobrac wants to merge 8 commits intomainfrom
feat/snapshots

Conversation

@dobrac
Copy link
Contributor

@dobrac dobrac commented Jan 31, 2026

Summary

Adds snapshot functionality to the SDK for creating persistent sandbox state that can be used to spawn new sandboxes.

Usage

JavaScript / TypeScript

// Create a snapshot from a running sandbox
const snapshot = await sandbox.createSnapshot()

// Or by sandbox ID
const snapshot = await Sandbox.createSnapshot(sandboxId)

// Create new sandbox from snapshot
const newSandbox = await Sandbox.create(snapshot.snapshotId)

// List snapshots
for await (const s of Sandbox.listSnapshots()) {
  console.log(s.snapshotId)
}

// Delete snapshot
await Sandbox.deleteSnapshot(snapshot.snapshotId)

Python (sync)

# Create a snapshot from a running sandbox
snapshot = sandbox.create_snapshot()

# Or by sandbox ID
snapshot = Sandbox.create_snapshot(sandbox_id)

# Create new sandbox from snapshot
new_sandbox = Sandbox.create(snapshot.snapshot_id)

# List snapshots
paginator = Sandbox.list_snapshots()
while paginator.has_next:
    snapshots = paginator.next_items()

# Delete snapshot
Sandbox.delete_snapshot(snapshot.snapshot_id)

Python (async)

# Create a snapshot from a running sandbox
snapshot = await sandbox.create_snapshot()

# Or by sandbox ID
snapshot = await AsyncSandbox.create_snapshot(sandbox_id)

# Create new sandbox from snapshot
new_sandbox = await AsyncSandbox.create(snapshot.snapshot_id)

# List snapshots
paginator = AsyncSandbox.list_snapshots()
while paginator.has_next:
    snapshots = await paginator.next_items()

# Delete snapshot
await AsyncSandbox.delete_snapshot(snapshot.snapshot_id)

API

JS SDK

  • sandbox.createSnapshot() - Create snapshot from current sandbox
  • Sandbox.createSnapshot(sandboxId) - Create snapshot by sandbox ID
  • Sandbox.listSnapshots() - List all snapshots (paginated, async iterable)
  • Sandbox.deleteSnapshot(snapshotId) - Delete a snapshot

Python SDK

  • sandbox.create_snapshot() / Sandbox.create_snapshot(sandbox_id) - Create snapshot
  • Sandbox.list_snapshots(sandbox_id=None) - List snapshots (paginated)
  • Sandbox.delete_snapshot(snapshot_id) - Delete a snapshot
  • Async variants on AsyncSandbox with the same signatures

Note

Medium Risk
Touches public SDK APIs and regenerates OpenAPI client code; incorrect mapping of new endpoints/schemas or deletion semantics could break existing integrations despite limited security exposure.

Overview
Adds persistent snapshot support across the JS and Python SDKs, including creating snapshots from a sandbox, listing snapshots with pagination (and async iteration in JS), and deleting snapshots.

Updates the OpenAPI spec and generated clients to introduce /sandboxes/{sandboxID}/snapshots and /snapshots, deprecate the legacy /sandboxes/{sandboxID}/logs in favor of /v2/sandboxes/{sandboxID}/logs, and add new schema surface (e.g. SnapshotInfo, volume mounts, and sandbox auto-resume config). Includes new snapshot-focused test suites and minor test robustness tweaks (switch to UUIDs; paginator now throws SandboxException).

Written by Cursor Bugbot for commit 881b310. This will update automatically on new commits. Configure here.

@dobrac dobrac added the feature New feature or request label Jan 31, 2026
@changeset-bot
Copy link

changeset-bot bot commented Jan 31, 2026

🦋 Changeset detected

Latest commit: 881b310

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
e2b Minor
@e2b/python-sdk Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dobrac dobrac force-pushed the feat/snapshots branch 2 times, most recently from 8a8e564 to ac979b8 Compare January 31, 2026 11:11
@dobrac dobrac force-pushed the feat/snapshots branch 4 times, most recently from 0696278 to 01ff8d1 Compare February 16, 2026 23:57
@dobrac dobrac force-pushed the feat/snapshots branch 3 times, most recently from b2b2db3 to 2ed5cdd Compare February 17, 2026 00:52
@github-actions
Copy link
Contributor

github-actions bot commented Feb 17, 2026

Package Artifacts

Built from b2a92c3. Download artifacts from this workflow run.

JS SDK (e2b@2.12.2-feat-snapshots.0):

npm install ./e2b-2.12.2-feat-snapshots.0.tgz

CLI (@e2b/cli@2.7.1-feat-snapshots.0):

npm install ./e2b-cli-2.7.1-feat-snapshots.0.tgz

Python SDK (e2b==2.13.2+feat-snapshots):

pip install ./e2b-2.13.2+feat.snapshots-py3-none-any.whl

@dobrac dobrac force-pushed the feat/snapshots branch 5 times, most recently from 305217c to f1206f3 Compare February 18, 2026 08:16
@dobrac dobrac marked this pull request as ready for review February 18, 2026 08:25
@dobrac dobrac changed the base branch from main to chore/random-bugfixes February 18, 2026 08:26
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f1206f378c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Choose a reason for hiding this comment

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

P2 Badge Use a default/public template in the JS snapshot example

The example now hardcodes Sandbox.create('dobrac-test-bugs-simple-0'), which is account-specific and will fail for users who do not have that template, so the published example is no longer runnable out of the box. This is a regression from the previous default-template flow and will block users trying to validate snapshot support quickly.

Useful? React with 👍 / 👎.

Comment on lines 40 to 41

Choose a reason for hiding this comment

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

P2 Badge Clean up sandboxes created by the snapshot example

The script creates two sandboxes (sandbox and sandbox2) but never calls kill() on either of them, so running this example leaves live sandboxes behind until TTL expiry. In real accounts this can consume quota/cost and is especially problematic when users repeatedly run the example while debugging.

Useful? React with 👍 / 👎.

Copy link

Choose a reason for hiding this comment

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

Hardcoded personal template in example file

Low Severity

The example file uses a hardcoded personal template 'dobrac-test-bugs-simple-0' in Sandbox.create(). The previous version used Sandbox.create() with no arguments (defaulting to the base template). This template name appears only in this file and is clearly team/developer-specific debug code. The example also no longer calls sandbox.kill() on either sandbox, leaking resources when run.

Fix in Cursor Fix in Web

Base automatically changed from chore/random-bugfixes to main February 18, 2026 10:37
Adds create, list, delete snapshot methods to both Sandbox
and AsyncSandbox classes with paginated listing support.
Renames JS SDK's sandbox.snapshot() to sandbox.createSnapshot()
for consistency. Includes OpenAPI spec updates for snapshots,
volumes, auto-resume, and v2 logs endpoint.
Co-authored-by: Cursor <cursoragent@cursor.com>

fix: regenerate API clients with snapshots tag and add missing body param

- Add 'snapshots' to codegen tag filter in JS SDK and Python SDK
- Add required body parameter to createSnapshot API call
- Regenerate all API clients from current OpenAPI spec

fix: add missing body param to Python SDK create_snapshot calls

fix: use unformatted schema.gen.ts output from openapi-typescript

These files are in .prettierignore and should not be reformatted.
…ests

Timestamp-based unique IDs caused flaky failures when parallel test
workers (async/sync variants) generated the same value within the same
second/millisecond.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

yield item
}
}
}
Copy link

Choose a reason for hiding this comment

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

Duplicated paginator boilerplate across JS SDK classes

Low Severity

SnapshotPaginator duplicates ~25 lines from SandboxPaginator — field declarations, constructor wiring (ConnectionConfig, ApiClient, _hasNext, _nextToken, limit), both property getters, and the [Symbol.asyncIterator]() method are identical. The Python SDK similarly introduces SnapshotPaginatorBase as a near-clone of SandboxPaginatorBase. A shared generic base class would eliminate this and ensure any future pagination bug fix applies to both.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Member

Choose a reason for hiding this comment

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

Seems reasonable, any reason to not do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

missed the comment, will do

Copy link
Member

@ValentaTomas ValentaTomas left a comment

Choose a reason for hiding this comment

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

Left a note in one of the bot notes, but otherwise lgtm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments