Puck.Sandbox.Runtime.Adapter behaviour (Puck v0.2.11)

Copy Markdown View Source

Behaviour for runtime sandbox adapters.

Adapters implement sandbox creation and management. Currently only the Test adapter is shipped. Custom adapters can be created by implementing this behaviour.

Required Callbacks

  • create/1 - Create a new sandbox, return its ID and metadata
  • exec/3 - Execute a command in the sandbox
  • terminate/2 - Stop and cleanup the sandbox
  • status/2 - Get the current sandbox status

Optional Callbacks

  • get_url/2 - Get URL for an exposed port
  • read_file/3 - Read file contents from sandbox
  • write_file/4 - Write file to sandbox
  • write_files/3 - Write multiple files to sandbox
  • await_ready/3 - Wait for sandbox to become ready
  • update/3 - Update sandbox config without destroying
  • stop/2 - Stop sandbox without destroying (pause)
  • start/2 - Start a stopped sandbox (resume)

Standard Config Fields

These config fields should work consistently across adapters:

  • :image - Container image (e.g., "node:22-slim")
  • :memory_mb - Memory limit in MB (e.g., 512)
  • :env - Environment variables as [{name, value}]
  • :ports - Ports to expose (format varies by adapter)
  • :mounts - Volume/file mounts (format varies by adapter)
  • :proxy - Enable proxy mode for controlled network access

Adapters may support additional adapter-specific config fields.

Example

defmodule MyAdapter do
  @behaviour Puck.Sandbox.Runtime.Adapter

  @impl true
  def create(config) do
    # Create sandbox, return {:ok, sandbox_id, metadata} or {:error, reason}
  end

  @impl true
  def exec(sandbox_id, command, opts) do
    # Execute command, return {:ok, %ExecResult{}} or {:error, reason}
  end

  @impl true
  def terminate(sandbox_id, opts) do
    # Cleanup sandbox, return :ok or {:error, reason}
  end

  @impl true
  def status(sandbox_id, opts) do
    # Return :running | :stopped | :terminated | :unknown
  end
end

Summary

Types

command()

@type command() :: String.t()

config()

@type config() :: map()

metadata()

@type metadata() :: map()

opts()

@type opts() :: keyword()

sandbox_id()

@type sandbox_id() :: String.t()

Callbacks

await_ready(sandbox_id, metadata, opts)

(optional)
@callback await_ready(sandbox_id(), metadata(), opts()) :: {:ok, map()} | {:error, term()}

create(config)

@callback create(config()) :: {:ok, sandbox_id(), metadata()} | {:error, term()}

exec(sandbox_id, command, opts)

@callback exec(sandbox_id(), command(), opts()) ::
  {:ok, Puck.Sandbox.Runtime.ExecResult.t()} | {:error, term()}

get_url(sandbox_id, port)

(optional)
@callback get_url(sandbox_id(), port :: integer()) :: {:ok, String.t()} | {:error, term()}

read_file(sandbox_id, path, opts)

(optional)
@callback read_file(sandbox_id(), path :: String.t(), opts()) ::
  {:ok, binary()} | {:error, term()}

start(sandbox_id, opts)

(optional)
@callback start(sandbox_id(), opts()) :: {:ok, map()} | {:error, term()}

status(sandbox_id, opts)

@callback status(sandbox_id(), opts()) :: :running | :stopped | :terminated | :unknown

stop(sandbox_id, opts)

(optional)
@callback stop(sandbox_id(), opts()) :: {:ok, map()} | {:error, term()}

terminate(sandbox_id, opts)

@callback terminate(sandbox_id(), opts()) :: :ok | {:error, term()}

update(sandbox_id, config, opts)

(optional)
@callback update(sandbox_id(), config(), opts()) :: {:ok, map()} | {:error, term()}

write_file(sandbox_id, path, content, opts)

(optional)
@callback write_file(sandbox_id(), path :: String.t(), content :: binary(), opts()) ::
  :ok | {:error, term()}

write_files(sandbox_id, files, opts)

(optional)
@callback write_files(sandbox_id(), files :: [{String.t(), binary()}], opts()) ::
  :ok | {:error, term()}