Actana

Sandbox

The ephemeral runtime that executes Crew agents and Assistant turns.

ScreenshotSandbox running an Assistant turn — step trace + token deltas.

The Sandbox is the ephemeral runtime that runs an agent loop against real tools, files, and skills. It is not a docs section about a UI surface — it is the runner that the Assistant and the Agents block both dispatch to.

A sandbox is fresh per dispatch. It boots, redeems one-time tokens for its configuration, runs the agent loop, streams NDJSON output back, optionally writes assets to the workspace file bag, and then dies. Nothing inside a sandbox is durable — only what the run streams or writes back persists.

Two callers, one runner

            ┌──────────────────────┐
            │  Assistant chat turn │ ─┐
            └──────────────────────┘  │
                                      ├──► POST {SANDBOX_URL}/stream
            ┌──────────────────────┐  │     (agent_url, otp_setup,
            │   Agents block run   │ ─┘      otp_run, otp_upload?, prompt)
            └──────────────────────┘
                                      ◄── NDJSON stream of
                                          { log | step | result | error }

Both callers share the same sandbox runner contract. The runner discriminates by the request body, not by path — /stream is the only endpoint. The chat backend transforms NDJSON to SSE before sending it to the browser; the Agents block surfaces it directly through the workflow run stream.

Three one-time tokens

Every dispatch mints three OTPs and stores hashed copies (crew_agent_otp for the Agents block; the Assistant uses an equivalent in-memory mint). The sandbox redeems them by calling back into the workspace API:

OTPEndpointLifetimePurpose
otp_setupGET {agentUrl}/env10 min (Agents)Fetch the named-environment variables + setup script.
otp_runGET {agentUrl}/config10 min (Agents)Fetch agent definition: system prompt, model, attached skills + MCP servers. For the Assistant, this returns the per-turn envelope.
otp_uploadPOST {agentUrl}/results (or /assets/writeback)60 minWrite generated assets back into the workspace's file bag. Optional — set only when the caller has opted into the bag system.

Each OTP is single-use. The sandbox redeems setup + run during boot, then the upload OTP at the end of the run if it produced files.

Lifecycle

  1. Mint — caller mints OTPs and inserts hashed copies scoped to this execution / chat turn.
  2. Dispatch — caller POSTs /stream to the sandbox runner with the agent URL, the three plaintext OTPs, and the prompt. The runner spawns a container.
  3. Bootstrap — the container calls ${AGENT_URL}/env and ${AGENT_URL}/config with the OTPs to load its environment and agent config.
  4. Run — the agent loop runs with model + skills + tools attached. Output streams back as NDJSON line by line.
  5. Writeback — if the run produced assets, the container POSTs them to ${AGENT_URL}/results using the upload OTP.
  6. Settle — the container exits; the caller closes the response stream.

Hard runtime cap

A sandbox is capped at ASSISTANT_SANDBOX_MAX_RUNTIME_SEC (default 8 hours, plus a 60-second grace before Next.js returns the route timeout). The cap matches the lifetime of the asbx_ bearer token the sandbox uses to call back into the workspace API.

What lives inside the sandbox

The container starts with:

  • The system prompt (from a Crew Agent, or the Assistant default).
  • The named environment's variables and setup script (run before the first model call).
  • Every attached skill bundle (actana_tables, actana_files, actana_workflow_editor for Assistant turns by default).
  • A workspace API base URL plus an asbx_ bearer for callbacks (creating files, reading tables, editing workflows).

Tool calls during the loop hit the model directly when they're MCP / OpenAI-style function calls, or hit the workspace API through skills (which in turn call back to the workspace).

See Streaming for the NDJSON envelope spec and Assets for how files written inside a run land in the workspace file store.

Configuration

SANDBOX_URL (sometimes ASSISTANT_SANDBOX_URL) is the HTTP base URL of the sandbox runner. The Agents block falls back to:

  1. Block input sandboxUrl
  2. Workflow environment SANDBOX_URL
  3. Server env SANDBOX_URL

If none is set the dispatch fails. The Assistant route uses assertAssistantSandboxRuntimeConfig to fail-fast at start-up rather than per-turn.

Source

  • apps/actana/lib/assistant-sandbox/sandbox-client.ts — provisioning client
  • apps/actana/lib/assistant-sandbox/envelope.ts — wire-format types
  • apps/actana/lib/assistant-sandbox/runtime-config.ts — env-driven config
  • apps/actana/app/api/assistant/sandbox/[sessionId]/ — sandbox callback routes (/env, /config, /results, /skills)
  • apps/actana/executor/handlers/agents/agents-handler.ts — Agents-block dispatch
  • apps/actana/app/api/assistant/chat/stream/route.ts — Assistant dispatch

On this page