Class: E2B::Sandbox

Inherits:
Object
  • Object
show all
Extended by:
SandboxHelpers
Defined in:
lib/e2b/sandbox.rb

Overview

Represents an E2B Sandbox instance

A Sandbox is an isolated cloud environment for running code, executing commands, and managing files securely. Create sandboxes using class methods or through Client.

Examples:

Create and use a sandbox

sandbox = E2B::Sandbox.create(template: "base", api_key: "your-key")

result = sandbox.commands.run("echo 'Hello'")
puts result.stdout

sandbox.files.write("/home/user/hello.txt", "Hello!")
sandbox.kill

Connect to an existing sandbox

sandbox = E2B::Sandbox.connect("sandbox-id", api_key: "your-key")
sandbox.commands.run("ls")

Constant Summary collapse

DEFAULT_DOMAIN =

Default domain for E2B sandboxes

"e2b.app"
DEFAULT_TIMEOUT =

Default sandbox timeout in seconds

300
DEFAULT_MCP_TEMPLATE =

Default template used when enabling MCP without an explicit template.

"mcp-gateway"
MCP_PORT =

MCP gateway port.

50005

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sandbox_data:, http_client:, api_key:, domain: DEFAULT_DOMAIN) ⇒ Sandbox

Initialize a new Sandbox instance

Parameters:

  • sandbox_data (Hash)

    Sandbox data from API response

  • http_client (API::HttpClient)

    HTTP client for API calls

  • api_key (String)

    API key for authentication

  • domain (String) (defaults to: DEFAULT_DOMAIN)

    E2B domain



262
263
264
265
266
267
268
269
# File 'lib/e2b/sandbox.rb', line 262

def initialize(sandbox_data:, http_client:, api_key:, domain: DEFAULT_DOMAIN)
  @http_client = http_client
  @api_key = api_key
  @domain = domain

  process_sandbox_data(sandbox_data)
  initialize_services
end

Instance Attribute Details

#alias_nameString? (readonly)

Returns Sandbox alias/name.

Returns:

  • (String, nil)

    Sandbox alias/name



49
50
51
# File 'lib/e2b/sandbox.rb', line 49

def alias_name
  @alias_name
end

#client_idString (readonly)

Returns Client ID.

Returns:

  • (String)

    Client ID



52
53
54
# File 'lib/e2b/sandbox.rb', line 52

def client_id
  @client_id
end

#commandsServices::Commands (readonly)

Returns Command execution service.

Returns:



82
83
84
# File 'lib/e2b/sandbox.rb', line 82

def commands
  @commands
end

#cpu_countInteger? (readonly)

Returns CPU count.

Returns:

  • (Integer, nil)

    CPU count



61
62
63
# File 'lib/e2b/sandbox.rb', line 61

def cpu_count
  @cpu_count
end

#end_atTime? (readonly)

Returns When the sandbox will timeout.

Returns:

  • (Time, nil)

    When the sandbox will timeout



58
59
60
# File 'lib/e2b/sandbox.rb', line 58

def end_at
  @end_at
end

#envd_access_tokenString? (readonly)

Returns Access token for envd authentication.

Returns:

  • (String, nil)

    Access token for envd authentication



76
77
78
# File 'lib/e2b/sandbox.rb', line 76

def envd_access_token
  @envd_access_token
end

#envd_versionString? (readonly)

Returns Envd version reported by the control plane.

Returns:

  • (String, nil)

    Envd version reported by the control plane



73
74
75
# File 'lib/e2b/sandbox.rb', line 73

def envd_version
  @envd_version
end

#filesServices::Filesystem (readonly)

Returns Filesystem service.

Returns:



85
86
87
# File 'lib/e2b/sandbox.rb', line 85

def files
  @files
end

#gitServices::Git (readonly)

Returns Git operations service.

Returns:



91
92
93
# File 'lib/e2b/sandbox.rb', line 91

def git
  @git
end

#memory_mbInteger? (readonly)

Returns Memory in MB.

Returns:

  • (Integer, nil)

    Memory in MB



64
65
66
# File 'lib/e2b/sandbox.rb', line 64

def memory_mb
  @memory_mb
end

#metadataHash (readonly)

Returns Metadata.

Returns:

  • (Hash)

    Metadata



67
68
69
# File 'lib/e2b/sandbox.rb', line 67

def 
  @metadata
end

#ptyServices::Pty (readonly)

Returns PTY (pseudo-terminal) service.

Returns:



88
89
90
# File 'lib/e2b/sandbox.rb', line 88

def pty
  @pty
end

#sandbox_idString (readonly) Also known as: id

Returns Unique sandbox ID.

Returns:

  • (String)

    Unique sandbox ID



43
44
45
# File 'lib/e2b/sandbox.rb', line 43

def sandbox_id
  @sandbox_id
end

#started_atTime? (readonly)

Returns When the sandbox was started.

Returns:

  • (Time, nil)

    When the sandbox was started



55
56
57
# File 'lib/e2b/sandbox.rb', line 55

def started_at
  @started_at
end

#stateString? (readonly)

Returns Current sandbox state.

Returns:

  • (String, nil)

    Current sandbox state



70
71
72
# File 'lib/e2b/sandbox.rb', line 70

def state
  @state
end

#template_idString (readonly)

Returns Template ID used to create this sandbox.

Returns:

  • (String)

    Template ID used to create this sandbox



46
47
48
# File 'lib/e2b/sandbox.rb', line 46

def template_id
  @template_id
end

#traffic_access_tokenString? (readonly)

Returns Access token required for proxied public traffic.

Returns:

  • (String, nil)

    Access token required for proxied public traffic



79
80
81
# File 'lib/e2b/sandbox.rb', line 79

def traffic_access_token
  @traffic_access_token
end

Class Method Details

.connect(sandbox_id, timeout: DEFAULT_TIMEOUT, api_key: nil, access_token: nil, domain: nil) ⇒ Sandbox

Connect to an existing running sandbox

Parameters:

  • sandbox_id (String)

    The sandbox ID to connect to

  • timeout (Integer, nil) (defaults to: DEFAULT_TIMEOUT)

    New timeout in seconds (extends TTL)

  • api_key (String, nil) (defaults to: nil)

    API key

  • domain (String) (defaults to: nil)

    E2B domain

Returns:

  • (Sandbox)

    The sandbox instance



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/e2b/sandbox.rb', line 162

def connect(sandbox_id, timeout: DEFAULT_TIMEOUT, api_key: nil, access_token: nil, domain: nil)
  credentials = resolve_credentials(api_key: api_key, access_token: access_token)
  domain = resolve_domain(domain)
  http_client = build_http_client(**credentials, domain: domain)

  response = http_client.post("/sandboxes/#{sandbox_id}/connect",
    body: { timeout: timeout || DEFAULT_TIMEOUT })

  new(
    sandbox_data: response,
    http_client: http_client,
    api_key: credentials[:api_key],
    domain: domain
  )
end

.create(template: "base", timeout: DEFAULT_TIMEOUT, metadata: nil, envs: nil, secure: true, allow_internet_access: true, network: nil, lifecycle: nil, auto_pause: nil, mcp: nil, api_key: nil, access_token: nil, domain: nil, request_timeout: 120) ⇒ Sandbox

Create a new sandbox

Examples:

sandbox = E2B::Sandbox.create(template: "base")
sandbox = E2B::Sandbox.create(template: "python", timeout: 600)

Parameters:

  • template (String) (defaults to: "base")

    Template ID or alias (default: “base”)

  • timeout (Integer) (defaults to: DEFAULT_TIMEOUT)

    Sandbox timeout in seconds (default: 300)

  • metadata (Hash, nil) (defaults to: nil)

    Custom metadata key-value pairs

  • envs (Hash{String => String}, nil) (defaults to: nil)

    Environment variables

  • api_key (String, nil) (defaults to: nil)

    API key (defaults to E2B_API_KEY env var)

  • domain (String) (defaults to: nil)

    E2B domain

  • request_timeout (Integer) (defaults to: 120)

    HTTP request timeout in seconds

Returns:

  • (Sandbox)

    The created sandbox instance



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/e2b/sandbox.rb', line 114

def create(template: "base", timeout: DEFAULT_TIMEOUT, metadata: nil,
           envs: nil, secure: true, allow_internet_access: true,
           network: nil, lifecycle: nil, auto_pause: nil, mcp: nil,
           api_key: nil, access_token: nil, domain: nil,
           request_timeout: 120)
  credentials = resolve_credentials(api_key: api_key, access_token: access_token)
  domain = resolve_domain(domain)
  http_client = build_http_client(**credentials, domain: domain)
  template = resolved_template(template, mcp: mcp)
  lifecycle = normalized_lifecycle(lifecycle: lifecycle, auto_pause: auto_pause)

  body = {
    templateID: template,
    timeout: timeout,
    secure: secure,
    allow_internet_access: allow_internet_access,
    autoPause: lifecycle[:on_timeout] == "pause"
  }
  body[:metadata] =  if 
  body[:envVars] = envs if envs
  body[:mcp] = mcp if mcp
  body[:network] = network if network
  if body[:autoPause]
    body[:autoResume] = { enabled: lifecycle[:auto_resume] }
  end

  response = http_client.post("/sandboxes", body: body, timeout: request_timeout)
  ensure_supported_envd_version!(response, http_client)

  sandbox = new(
    sandbox_data: response,
    http_client: http_client,
    api_key: credentials[:api_key],
    domain: domain
  )

  start_mcp_gateway(sandbox, mcp) if mcp

  sandbox
end

.delete_snapshot(snapshot_id, api_key: nil, access_token: nil, domain: nil) ⇒ Boolean

Delete a snapshot template.

Parameters:

  • snapshot_id (String)

    Snapshot identifier

Returns:

  • (Boolean)

    true if deleted, false if not found



223
224
225
226
227
228
229
230
# File 'lib/e2b/sandbox.rb', line 223

def delete_snapshot(snapshot_id, api_key: nil, access_token: nil, domain: nil)
  credentials = resolve_credentials(api_key: api_key, access_token: access_token)
  http_client = build_http_client(**credentials, domain: resolve_domain(domain))
  http_client.delete("/templates/#{snapshot_id}")
  true
rescue E2B::NotFoundError
  false
end

.kill(sandbox_id, api_key: nil, access_token: nil, domain: nil) ⇒ Boolean

Kill a sandbox by ID (idempotent)

Returns ‘true` if the sandbox was killed, and if it was already gone (NotFound). To distinguish “actually killed” from “already gone”, use list or #running? before calling.

Parameters:

  • sandbox_id (String)

    Sandbox ID to kill

  • api_key (String, nil) (defaults to: nil)

    API key

Returns:

  • (Boolean)

    always true



241
242
243
244
245
246
247
248
# File 'lib/e2b/sandbox.rb', line 241

def kill(sandbox_id, api_key: nil, access_token: nil, domain: nil)
  credentials = resolve_credentials(api_key: api_key, access_token: access_token)
  http_client = build_http_client(**credentials, domain: resolve_domain(domain))
  http_client.delete("/sandboxes/#{sandbox_id}")
  true
rescue E2B::NotFoundError
  true
end

.list(query: nil, limit: 100, next_token: nil, api_key: nil, access_token: nil, domain: nil) ⇒ SandboxPaginator

List running sandboxes

Returns a paginator that yields sandbox info hashes one page at a time. Use BasePaginator#has_next? and BasePaginator#next_items to iterate through pages.

Parameters:

  • query (Hash, nil) (defaults to: nil)

    Filter parameters (metadata, state)

  • limit (Integer) (defaults to: 100)

    Maximum results per page

  • next_token (String, nil) (defaults to: nil)

    Pagination token

  • api_key (String, nil) (defaults to: nil)

    API key

Returns:



189
190
191
192
193
194
195
196
197
198
199
# File 'lib/e2b/sandbox.rb', line 189

def list(query: nil, limit: 100, next_token: nil, api_key: nil, access_token: nil, domain: nil)
  credentials = resolve_credentials(api_key: api_key, access_token: access_token)
  http_client = build_http_client(**credentials, domain: resolve_domain(domain))

  SandboxPaginator.new(
    http_client: http_client,
    query: query,
    limit: limit,
    next_token: next_token
  )
end

.list_snapshots(sandbox_id: nil, limit: 100, next_token: nil, api_key: nil, access_token: nil, domain: nil) ⇒ SnapshotPaginator

List snapshots for the team, optionally filtered by source sandbox.

Parameters:

  • sandbox_id (String, nil) (defaults to: nil)

    Filter snapshots by source sandbox ID

  • limit (Integer) (defaults to: 100)

    Maximum results per page

  • next_token (String, nil) (defaults to: nil)

    Pagination token

Returns:



207
208
209
210
211
212
213
214
215
216
217
# File 'lib/e2b/sandbox.rb', line 207

def list_snapshots(sandbox_id: nil, limit: 100, next_token: nil, api_key: nil, access_token: nil, domain: nil)
  credentials = resolve_credentials(api_key: api_key, access_token: access_token)
  http_client = build_http_client(**credentials, domain: resolve_domain(domain))

  SnapshotPaginator.new(
    http_client: http_client,
    sandbox_id: sandbox_id,
    limit: limit,
    next_token: next_token
  )
end

Instance Method Details

#connect(timeout: nil) ⇒ Object

Deprecated.

Use #resume instead. The instance-level ‘#connect` collides in name with the class-level connect, which has different semantics (it builds a new Sandbox instance from a sandbox_id). The instance method only resumes the current sandbox.

Parameters:

  • timeout (Integer, nil) (defaults to: nil)

    New timeout in seconds



330
331
332
333
334
335
336
# File 'lib/e2b/sandbox.rb', line 330

def connect(timeout: nil)
  warn "[DEPRECATION] Sandbox#connect is deprecated; use Sandbox#resume " \
       "instead. (Sandbox.connect class method is unchanged.) " \
       "Called from #{caller(1, 1).first}"
  resume(timeout: timeout)
  self
end

#create_snapshotHash

Create a snapshot of the sandbox

Returns:

  • (Hash)

    Snapshot info with snapshot_id



351
352
353
354
# File 'lib/e2b/sandbox.rb', line 351

def create_snapshot
  response = @http_client.post("/sandboxes/#{@sandbox_id}/snapshots")
  Models::SnapshotInfo.from_hash(response)
end

#download_url(path, user: nil, use_signature_expiration: nil) ⇒ String

Get URL for downloading a file

Parameters:

  • path (String)

    File path in the sandbox

  • user (String, nil) (defaults to: nil)

    Username context

Returns:

  • (String)

    Download URL



406
407
408
409
410
411
412
413
414
415
416
# File 'lib/e2b/sandbox.rb', line 406

def download_url(path, user: nil, use_signature_expiration: nil)
  user = resolve_legacy_file_user(user)
  query = build_file_url_query(
    path: path,
    user: user,
    operation: "read",
    use_signature_expiration: use_signature_expiration
  )
  base = "https://#{Services::BaseService::ENVD_PORT}-#{@sandbox_id}.#{@domain}/files"
  query.empty? ? base : "#{base}?#{URI.encode_www_form(query)}"
end

#get_host(port) ⇒ String

Get the host string for a port (without protocol)

Parameters:

  • port (Integer)

    Port number

Returns:

  • (String)

    Host string like “4321-abc123.e2b.app”



389
390
391
# File 'lib/e2b/sandbox.rb', line 389

def get_host(port)
  "#{port}-#{@sandbox_id}.#{@domain}"
end

#get_infoHash

Get sandbox info from the API

Returns:

  • (Hash)

    Sandbox info



274
275
276
277
278
# File 'lib/e2b/sandbox.rb', line 274

def get_info
  response = @http_client.get("/sandboxes/#{@sandbox_id}")
  process_sandbox_data(response)
  response
end

#get_mcp_tokenString?

Get the MCP token for the sandbox.

Returns:

  • (String, nil)


381
382
383
# File 'lib/e2b/sandbox.rb', line 381

def get_mcp_token
  @mcp_token ||= @files.read("/etc/mcp-gateway/.token", user: "root")
end

#get_mcp_urlString

Get the MCP URL for the sandbox.

Returns:

  • (String)


374
375
376
# File 'lib/e2b/sandbox.rb', line 374

def get_mcp_url
  "https://#{get_host(MCP_PORT)}/mcp"
end

#get_metrics(start_time: nil, end_time: nil) ⇒ Array<Hash>

Get sandbox metrics (CPU, memory, disk usage)

Parameters:

  • start_time (Time, nil) (defaults to: nil)

    Metrics start time

  • end_time (Time, nil) (defaults to: nil)

    Metrics end time

Returns:

  • (Array<Hash>)

    Metrics data



440
441
442
443
444
445
446
# File 'lib/e2b/sandbox.rb', line 440

def get_metrics(start_time: nil, end_time: nil)
  params = {}
  params[:start] = start_time.iso8601 if start_time
  params[:end] = end_time.iso8601 if end_time

  @http_client.get("/sandboxes/#{@sandbox_id}/metrics", params: params)
end

#get_url(port) ⇒ String

Get full URL for a port

Parameters:

  • port (Integer)

    Port number

Returns:



397
398
399
# File 'lib/e2b/sandbox.rb', line 397

def get_url(port)
  "https://#{get_host(port)}"
end

#killBoolean

Kill/terminate the sandbox (idempotent)

Returns ‘true` whether the sandbox was running or already gone.

Returns:

  • (Boolean)

    always true



311
312
313
314
315
316
# File 'lib/e2b/sandbox.rb', line 311

def kill
  @http_client.delete("/sandboxes/#{@sandbox_id}")
  true
rescue E2B::NotFoundError
  true
end

#list_snapshots(limit: 100, next_token: nil) ⇒ SnapshotPaginator

List snapshots that were created from this sandbox.

Parameters:

  • limit (Integer) (defaults to: 100)

    Maximum results per page

  • next_token (String, nil) (defaults to: nil)

    Pagination token

Returns:



361
362
363
364
365
366
367
368
369
# File 'lib/e2b/sandbox.rb', line 361

def list_snapshots(limit: 100, next_token: nil)
  self.class.list_snapshots(
    sandbox_id: @sandbox_id,
    limit: limit,
    next_token: next_token,
    api_key: @api_key,
    domain: @domain
  )
end

#logs(start_time: nil, limit: 100) ⇒ Array<Hash>

Get sandbox logs

Parameters:

  • start_time (Time, nil) (defaults to: nil)

    Start time for logs

  • limit (Integer) (defaults to: 100)

    Maximum number of log entries

Returns:

  • (Array<Hash>)

    Log entries



453
454
455
456
457
458
459
# File 'lib/e2b/sandbox.rb', line 453

def logs(start_time: nil, limit: 100)
  params = { limit: limit }
  params[:start] = start_time.iso8601 if start_time

  response = @http_client.get("/sandboxes/#{@sandbox_id}/logs", params: params)
  response.is_a?(Hash) ? (response["logs"] || []) : response
end

#pauseObject

Pause the sandbox (saves state for later resume)



319
320
321
322
# File 'lib/e2b/sandbox.rb', line 319

def pause
  @http_client.post("/sandboxes/#{@sandbox_id}/pause")
  @state = "paused"
end

#resume(timeout: nil) ⇒ Object

Resume a paused sandbox

Parameters:

  • timeout (Integer, nil) (defaults to: nil)

    New timeout in seconds



341
342
343
344
345
346
# File 'lib/e2b/sandbox.rb', line 341

def resume(timeout: nil)
  body = { timeout: timeout || DEFAULT_TIMEOUT }

  response = @http_client.post("/sandboxes/#{@sandbox_id}/connect", body: body)
  process_sandbox_data(response) if response.is_a?(Hash)
end

#running?(request_timeout: 10) ⇒ Boolean

Check if the sandbox is running

Parameters:

  • request_timeout (Integer) (defaults to: 10)

    Request timeout in seconds

Returns:

  • (Boolean)


284
285
286
287
288
289
290
291
# File 'lib/e2b/sandbox.rb', line 284

def running?(request_timeout: 10)
  return false if @end_at && Time.now >= @end_at

  get_info
  @state != "paused"
rescue NotFoundError, E2BError
  false
end

#set_timeout(timeout) ⇒ Object

Set the sandbox timeout

Parameters:

  • timeout (Integer)

    Timeout in seconds

Raises:

  • (ArgumentError)


296
297
298
299
300
301
302
303
304
# File 'lib/e2b/sandbox.rb', line 296

def set_timeout(timeout)
  raise ArgumentError, "Timeout must be positive" if timeout <= 0
  raise ArgumentError, "Timeout cannot exceed 24 hours (86400s)" if timeout > 86_400

  @http_client.post("/sandboxes/#{@sandbox_id}/timeout",
    body: { timeout: timeout })

  @end_at = Time.now + timeout
end

#time_remainingInteger

Time remaining until sandbox timeout

Returns:

  • (Integer)

    Seconds remaining, 0 if expired or unknown



464
465
466
467
468
469
# File 'lib/e2b/sandbox.rb', line 464

def time_remaining
  return 0 if @end_at.nil?

  remaining = (@end_at - Time.now).to_i
  remaining.positive? ? remaining : 0
end

#upload_url(path = nil, user: nil, use_signature_expiration: nil) ⇒ String

Get URL for uploading a file

Parameters:

  • path (String, nil) (defaults to: nil)

    Destination path

  • user (String, nil) (defaults to: nil)

    Username context

Returns:

  • (String)

    Upload URL



423
424
425
426
427
428
429
430
431
432
433
# File 'lib/e2b/sandbox.rb', line 423

def upload_url(path = nil, user: nil, use_signature_expiration: nil)
  user = resolve_legacy_file_user(user)
  base = "https://#{Services::BaseService::ENVD_PORT}-#{@sandbox_id}.#{@domain}/files"
  query = build_file_url_query(
    path: path,
    user: user,
    operation: "write",
    use_signature_expiration: use_signature_expiration
  )
  query.empty? ? base : "#{base}?#{URI.encode_www_form(query)}"
end