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:
| OTP | Endpoint | Lifetime | Purpose |
|---|---|---|---|
otp_setup | GET {agentUrl}/env | 10 min (Agents) | Fetch the named-environment variables + setup script. |
otp_run | GET {agentUrl}/config | 10 min (Agents) | Fetch agent definition: system prompt, model, attached skills + MCP servers. For the Assistant, this returns the per-turn envelope. |
otp_upload | POST {agentUrl}/results (or /assets/writeback) | 60 min | Write 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
- Mint — caller mints OTPs and inserts hashed copies scoped to this execution / chat turn.
- Dispatch — caller POSTs
/streamto the sandbox runner with the agent URL, the three plaintext OTPs, and the prompt. The runner spawns a container. - Bootstrap — the container calls
${AGENT_URL}/envand${AGENT_URL}/configwith the OTPs to load its environment and agent config. - Run — the agent loop runs with model + skills + tools attached. Output streams back as NDJSON line by line.
- Writeback — if the run produced assets, the container POSTs them to
${AGENT_URL}/resultsusing the upload OTP. - 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_editorfor 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).
Configuration
SANDBOX_URL (sometimes ASSISTANT_SANDBOX_URL) is the HTTP base URL of the sandbox runner. The Agents block falls back to:
- Block input
sandboxUrl - Workflow environment
SANDBOX_URL - 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 clientapps/actana/lib/assistant-sandbox/envelope.ts— wire-format typesapps/actana/lib/assistant-sandbox/runtime-config.ts— env-driven configapps/actana/app/api/assistant/sandbox/[sessionId]/— sandbox callback routes (/env,/config,/results,/skills)apps/actana/executor/handlers/agents/agents-handler.ts— Agents-block dispatchapps/actana/app/api/assistant/chat/stream/route.ts— Assistant dispatch