Long-running command sessions inside a sandbox.
Where ExDaytona.Sandbox.exec/3 runs one command to completion, a
session is a persistent shell: commands share state (working directory,
environment) and can run asynchronously — start a command, poll or
stream its logs, and collect its exit code when it finishes.
{:ok, session} = ExDaytona.Session.create(sandbox)
# Synchronous: waits for the command
{:ok, %{exit_code: 0, output: out}} = ExDaytona.Session.run(session, "echo hi")
# Asynchronous: start, follow the logs, then reap the exit code
{:ok, cmd_id} = ExDaytona.Session.run_async(session, "sleep 5 && echo done")
:ok = ExDaytona.Session.stream_logs(session, cmd_id, &IO.write/1)
{:ok, %{exit_code: 0}} = ExDaytona.Session.await(session, cmd_id)
:ok = ExDaytona.Session.delete(session)
Summary
Functions
Poll until the command finishes, then return
{:ok, %{exit_code: integer, command: String.t()}}.
A command's current state (ExDaytona.Model.Command) — exitCode is
nil while it is still running.
Create a session in the sandbox.
Delete the session. Returns :ok.
The sandbox's entrypoint session (where a configured entrypoint runs),
as an ExDaytona.Model.Session.
The entrypoint's logs so far, as a binary (fetched raw — see logs/2
for why the generated operation is bypassed).
Fetch a session's current state (its command history) as an
ExDaytona.Model.Session.
List the sandbox's sessions as ExDaytona.Model.Session structs.
The logs a command has produced so far, as a binary (stdout and stderr merged, as the sandbox emits them).
Open a structured, bounded log stream for a command — separate
:stdout/:stderr events over the provider's websocket protocol,
pull-based via ExDaytona.LogStream.next/2. See ExDaytona.LogStream
for the full contract (ownership, bounds, timeouts, close semantics).
Run a command in the session and wait for it to finish.
Start a command in the session without waiting. Returns
{:ok, cmd_id} — follow it with stream_logs/4, logs/2, and
await/3.
Send input to an interactive command's stdin (e.g. answering a
confirmation prompt). Returns :ok.
Follow a command's logs in real time: fun is invoked with each chunk
as the sandbox produces it, and the call returns :ok when the stream
closes (the command finished). Returning :halt from fun cancels
the stream.
Types
@type t() :: %ExDaytona.Session{id: String.t(), sandbox: ExDaytona.Sandbox.t()}
A session bound to the sandbox it runs in.
Functions
@spec await(t(), String.t(), keyword()) :: {:ok, %{exit_code: integer(), command: String.t() | nil}} | {:error, ExDaytona.Error.t()}
Poll until the command finishes, then return
{:ok, %{exit_code: integer, command: String.t()}}.
Options: :timeout (default 120_000 ms), :poll_interval
(default 1_000 ms).
@spec command(t(), String.t()) :: {:ok, ExDaytona.Model.Command.t()} | {:error, ExDaytona.Error.t()}
A command's current state (ExDaytona.Model.Command) — exitCode is
nil while it is still running.
@spec create( ExDaytona.Sandbox.t(), keyword() ) :: {:ok, t()} | {:error, ExDaytona.Error.t()}
Create a session in the sandbox.
Options: :id — the session id (default: a generated
"ex-daytona-" id).
@spec delete(t()) :: :ok | {:error, ExDaytona.Error.t()}
Delete the session. Returns :ok.
@spec entrypoint(ExDaytona.Sandbox.t()) :: {:ok, ExDaytona.Model.Session.t()} | {:error, ExDaytona.Error.t()}
The sandbox's entrypoint session (where a configured entrypoint runs),
as an ExDaytona.Model.Session.
@spec entrypoint_logs(ExDaytona.Sandbox.t()) :: {:ok, binary()} | {:error, ExDaytona.Error.t()}
The entrypoint's logs so far, as a binary (fetched raw — see logs/2
for why the generated operation is bypassed).
@spec get(t()) :: {:ok, ExDaytona.Model.Session.t()} | {:error, ExDaytona.Error.t()}
Fetch a session's current state (its command history) as an
ExDaytona.Model.Session.
@spec list(ExDaytona.Sandbox.t()) :: {:ok, [ExDaytona.Model.Session.t()]} | {:error, ExDaytona.Error.t()}
List the sandbox's sessions as ExDaytona.Model.Session structs.
@spec logs(t(), String.t()) :: {:ok, binary()} | {:error, ExDaytona.Error.t()}
The logs a command has produced so far, as a binary (stdout and stderr merged, as the sandbox emits them).
Note: the OpenAPI spec declares a JSON model for this endpoint, but the
live server returns text/plain — so this bypasses the generated
operation and reads the raw body.
@spec open_log_stream(t(), String.t(), keyword()) :: {:ok, pid()} | {:error, ExDaytona.Error.t()}
Open a structured, bounded log stream for a command — separate
:stdout/:stderr events over the provider's websocket protocol,
pull-based via ExDaytona.LogStream.next/2. See ExDaytona.LogStream
for the full contract (ownership, bounds, timeouts, close semantics).
Options are passed to ExDaytona.LogStream.open/3
(:owner, :max_buffer_bytes, :max_frames, :max_frame_bytes,
:idle_timeout, :overall_timeout, :connect_timeout).
@spec run(t(), String.t()) :: {:ok, %{ cmd_id: String.t() | nil, exit_code: integer() | nil, output: String.t() | nil, stdout: String.t() | nil, stderr: String.t() | nil }} | {:error, ExDaytona.Error.t()}
Run a command in the session and wait for it to finish.
Returns {:ok, %{cmd_id, exit_code, output, stdout, stderr}}.
@spec run_async(t(), String.t(), keyword()) :: {:ok, String.t()} | {:error, ExDaytona.Error.t()}
Start a command in the session without waiting. Returns
{:ok, cmd_id} — follow it with stream_logs/4, logs/2, and
await/3.
@spec send_input(t(), String.t(), iodata()) :: :ok | {:error, ExDaytona.Error.t()}
Send input to an interactive command's stdin (e.g. answering a
confirmation prompt). Returns :ok.
@spec stream_logs(t(), String.t(), (binary() -> any()), keyword()) :: :ok | {:error, ExDaytona.Error.t()}
Follow a command's logs in real time: fun is invoked with each chunk
as the sandbox produces it, and the call returns :ok when the stream
closes (the command finished). Returning :halt from fun cancels
the stream.
Merged output
This HTTP follow delivers stdout and stderr merged, exactly as 0.1.0
did. For separated, bounded, pull-based streaming use
open_log_stream/3 / ExDaytona.LogStream.
Options: :timeout — max milliseconds to wait between chunks
(default :infinity); :deadline — overall milliseconds for the
stream.