Omni.Tools.Repl.Sandbox (Omni Tools v0.1.0)

Copy Markdown View Source

Executes Elixir code in an isolated peer node.

Each invocation starts a fresh Erlang peer node, evaluates the code, captures IO output and the raw return value, then stops the peer. Clean slate per execution — no state carries over between calls.

The host's code paths are injected into the peer, so all compiled modules (including application dependencies) are available. In dev, Mix.install/1 can add additional dependencies since each peer is a fresh VM.

The sandbox executes arbitrary code with full system access. It is best-effort isolation, not a security boundary. For trusted use cases only: agent-driven experimentation, scratchpad computation — not adversarial input.

Options

  • :timeout - execution timeout in milliseconds (default: 60_000)
  • :max_output - truncation limit in bytes (default: 50_000)
  • :setup - code evaluated in the peer before the user's code. Setup runs before IO capture begins, so its output is not included. Accepts a string, quoted AST, or a list of either.

Return values

{:ok, %{output: "hello\n", result: :ok}}
{:error, :timeout, %{output: "partial..."}}
{:error, {:error, %ArithmeticError{}, stacktrace}, %{output: ""}}

On success, result is the raw return value of the last expression (not inspected). On error, the second element is either :timeout, :noconnection, or a {kind, reason, stacktrace} triple from the caught exception.

Summary

Types

Result of a sandbox evaluation — success, timeout/disconnect, or exception.

Functions

Enables distributed mode on the host VM if not already active.

Evaluates code in a fresh peer node and returns the captured output and raw return value.

Types

result()

@type result() ::
  {:ok, %{output: String.t(), result: term()}}
  | {:error, :timeout | :noconnection, %{output: String.t()}}
  | {:error, {atom(), term(), Exception.stacktrace()}, %{output: String.t()}}

Result of a sandbox evaluation — success, timeout/disconnect, or exception.

Functions

ensure_distributed!()

@spec ensure_distributed!() :: :ok

Enables distributed mode on the host VM if not already active.

Peer nodes require the host to be distributed (Node.alive?()). When the VM was started without --sname / --name, this function starts EPMD and enables distribution with a unique short name.

Called automatically by run/2 on each invocation (idempotent). You may also call it explicitly at application boot to avoid flipping the VM into distributed mode during a request — that flip can invalidate any PID-based state (encoded tokens, cached process references, etc.) that was created before distribution was enabled.

# In your Application.start/2:
Omni.Tools.Repl.Sandbox.ensure_distributed!()

run(code, opts \\ [])

@spec run(
  String.t(),
  keyword()
) :: result()

Evaluates code in a fresh peer node and returns the captured output and raw return value.