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.

50_005

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



259
260
261
262
263
264
265
266
# File 'lib/e2b/sandbox.rb', line 259

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



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

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
# 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
  body[:autoResume] = { enabled: lifecycle[:auto_resume] } if body[:autoPause]

  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



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

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



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

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:



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

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:



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

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



327
328
329
330
331
332
333
# File 'lib/e2b/sandbox.rb', line 327

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



348
349
350
351
# File 'lib/e2b/sandbox.rb', line 348

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



403
404
405
406
407
408
409
410
411
412
413
# File 'lib/e2b/sandbox.rb', line 403

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”



386
387
388
# File 'lib/e2b/sandbox.rb', line 386

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

#get_infoHash

Get sandbox info from the API

Returns:

  • (Hash)

    Sandbox info



271
272
273
274
275
# File 'lib/e2b/sandbox.rb', line 271

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)


378
379
380
# File 'lib/e2b/sandbox.rb', line 378

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)


371
372
373
# File 'lib/e2b/sandbox.rb', line 371

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



437
438
439
440
441
442
443
# File 'lib/e2b/sandbox.rb', line 437

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:



394
395
396
# File 'lib/e2b/sandbox.rb', line 394

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



308
309
310
311
312
313
# File 'lib/e2b/sandbox.rb', line 308

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:



358
359
360
361
362
363
364
365
366
# File 'lib/e2b/sandbox.rb', line 358

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



450
451
452
453
454
455
456
# File 'lib/e2b/sandbox.rb', line 450

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)



316
317
318
319
# File 'lib/e2b/sandbox.rb', line 316

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



338
339
340
341
342
343
# File 'lib/e2b/sandbox.rb', line 338

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)


281
282
283
284
285
286
287
288
# File 'lib/e2b/sandbox.rb', line 281

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)


293
294
295
296
297
298
299
300
301
# File 'lib/e2b/sandbox.rb', line 293

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



461
462
463
464
465
466
# File 'lib/e2b/sandbox.rb', line 461

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



420
421
422
423
424
425
426
427
428
429
430
# File 'lib/e2b/sandbox.rb', line 420

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