One process per streaming E2B command: owns the Connect stream, translates
envd events into the Managoat.Sandbox owner-frame contract, and
heartbeats the sandbox TTL while the command lives.
E2B sandboxes always carry a TTL, so a long agent turn must keep extending
it — a missed heartbeat degrades to an auto-pause (state preserved), never
a kill, because the adapter creates sandboxes with autoPause: true.
Frame mapping (envd StartResponse/ConnectResponse events, JSON codec):
data.stdout/data.stderr(base64) →{:stdout | :stderr, %{ref: ref}, bin}end.exitCode→{:exit, %{ref: ref}, code}- EndStream (flag 2) with an error →
{:error, %{ref: ref}, reason} - EndStream without a preceding end event →
{:exit, %{ref: ref}, 0}— the server finished the stream deliberately; per the contract a close without an exit frame reads as success - transport failure →
{:error, %{ref: ref}, reason}— the process may still be running sandbox-side; reattach exists for exactly this
In :attach mode the stream is a tail-based replayer over the journal
files the spawn shim wrote (see Managoat.Sandbox.E2B), so the buffered
output replays from byte zero; the real exit code is read from the shim's
exit file when the replayer ends.
Summary
Functions
Block until envd acknowledges the process (its start event, always the
stream's first frame) or the stream dies first.
Returns a specification to start this module under a supervisor.
Functions
Block until envd acknowledges the process (its start event, always the
stream's first frame) or the stream dies first.
Spawn must not return before this: the caller's first write_stdin —
the ACP peer writes initialize immediately — addresses the process by
tag, and a SendInput that races envd's registration 404s, which reads as
"process exited" and fails the turn before it began. Measured live on
prod (2026-08-14): the race lost twice in a row at ~300ms.
Returns a specification to start this module under a supervisor.
See Supervisor.