Intent
Once you have run a demo in which an agent calls a single tool inside BoxLite, the next and harder problem is this: how do you turn that demo into a production agent that can carry real traffic? In a production setup, each agent session gets its own fast-starting, disposable microVM; tool calls are sandboxed; resources are bounded by quotas; secrets never enter the prompt; and failures can be caught and retried. This page is a navigation page. It does not document individual APIs (those live on the feature pages). Instead it lays out a route from scattered capabilities to a production-grade agent, and points to the docs-v2 page for each step. After reading this page you should be able to answer:- Why give each agent session its own sandbox? (isolation, quotas, rollback)
- What does a production agent consist of? (sandbox + tool layer + secrets + lifecycle governance + observability)
- In what order do you fill in those pieces, from demo to production?
- You have read Quickstart (Python) and
- You understand the box lifecycle mental model (see
Manage Sandbox): the
Boxliteruntime is a synchronous context manager, whileSimpleBox/CodeBoxand the other box types are asynchronous context managers.
Mental model: one agent session = one sandbox
An LLM agent is a loop: the model emits a tool call -> it is executed somewhere -> the result is returned to the model -> repeat. Replacing “somewhere” with a BoxLite box gives you the capabilities a production agent needs:
The core principle: one agent session maps to one box; when the session ends,
the box is discarded. Under high concurrency, give each user/session its own
named box and let the runtime govern them.
Quick Example (minimal happy path)
Below is a minimal, runnable tool-execution loop for an agent: it runs the command “the model wants to execute” inside a sandbox, checks the exit code, and formats the result into a string you can feed back to the model. A hardcoded tool call stands in for real LLM output so you can copy and run it directly; when you wire in a real model, replacetool_call with the model’s returned
tool call.
@boxlite-ai/boxlite, SimpleBox cleans up via await using, and the exec timeout option is timeoutSecs.
For a complete tool loop where a real LLM drives the sandbox, see Drive a sandbox from your agent loop.
From demo to production: a step-by-step route
You can promote a demo to a production agent in the following five steps. Each step states the problem it solves and the feature page it maps to.Step 1: Choose the right Box type
Different agent tools map to different box types; you do not have to assemble everything from a bareSimpleBox.
For an overview and selection guidance per type, see
Box types.
Step 2: Set resource quotas and isolation for tool calls
A production agent must assume the model will generate runaway code, and should use quotas and security options to bound its impact.- Configure
cpus/memory_mib/disk_size_gb(if not passed explicitly, the underlying engine allocates a default; setting them explicitly is recommended in production): see Compute Resources. - Tighten networking (all outbound is allowed by default; you can switch to an allowlist or disable it entirely): see Network Access.
- Enable the strongest isolation:
BoxOptions(advanced=AdvancedBoxOptions(security=SecurityOptions.maximum())): see Secrets and Security.
Step 3: Provide secrets to tools without putting them in the prompt
An agent’s tools often need API keys (search, databases, third-party services). Do not splice secrets into the model’s prompt or into bare environment variables. UseSecret, which scopes usage to a target host and injects the
value via a placeholder.
Step 4: Govern the session lifecycle
Under high concurrency you have one box per session, and the runtime (Boxlite / JsBoxlite) is responsible for its creation, reuse, and reclaim.
- One-shot sessions: use the wrapper’s
async with+auto_remove=True(default); discard on exit. - Long-lived / cross-process reuse: use named boxes with
runtime.get_or_create(...), and explicitly callruntime.remove(id_or_name, force=)to reclaim. - Key constraint: removal and listing are the runtime’s responsibility ---
runtime.remove(...)/runtime.list_info(), notbox.remove()/runtime.list().
Step 5: Add observability and state rollback
A production agent should support monitoring and recover from bad states.- Metrics:
runtime.metrics()exposesRuntimeMetrics.num_running_boxes/boxes_created_total/boxes_failed_total;box.metrics()exposes per-sessionBoxMetrics.cpu_percent/memory_bytes. - Checkpoints and retries: call
box.snapshot.create(...)on a half-executed box, and after an error userestore(...)to return to the checkpoint instead of re-running from scratch. See Snapshots.
Parameters and Returns (key entry points per step)
The table below summarizes the core API entry points used in this route, so you can jump to the corresponding feature page for parameter details.Theexectimeout parameter differs in name/type across surfaces: the wrapperSimpleBox.exec(timeout=...)takes a float (seconds); Node uses{ timeoutSecs }; the nativeBox.execusestimeout_secs.CodeBox.run’stimeoutis an int.
ExecResult (return value of each tool call)
Troubleshooting
An agent tool appears not to error, but has actually failed
When anexec command exits with a non-zero code, it does not raise;
instead it returns ExecResult(exit_code != 0). If your tool-execution function
does not check the exit code, it will report a failure to the model as a
success, and the agent’s output will drift step by step. Check
result.exit_code (Node: result.exitCode) after every tool call, and feed
the failure back as an observation so the model can self-correct.
A missing command / image pull failure does not raise BoxliteError
A missing command or an image pull failure raises a standard RuntimeError (Python) / bare Error (Node), not BoxliteError. See Error Handling.
A Secret value was spliced directly into the prompt
The point of Secret is to keep the secret out of the prompt and out of
logs. Do not write the cleartext into the system prompt so the model
“knows” a key exists. Put the secret in
BoxOptions(secrets=[Secret(...)]), and let the tool use it inside the sandbox
via environment variable/placeholder. See
Secrets and Security.
Calling the nonexistent box.remove() / runtime.list()
This is easy to hit during high-concurrency governance: removal and listing are
the runtime’s responsibility.
- Use
runtime.remove(id_or_name, force=False), notbox.remove(). - Use
runtime.list_info(), notruntime.list().
Confusing the synchronous and asynchronous context managers
- The
Boxliteruntime’s context-manager protocol is synchronous: usewith Boxlite(...) as runtime:, notasync with(it has no__aenter__/__aexit__). This constraint applies only to entering/leaving the context; the runtime’s data methods (create/get_or_create/list_info/remove/metrics/shutdown) still requireawaitunder the async API. SimpleBox/CodeBoxand the other boxes are asyncasync with, and their methods requireawait(with the exception ofBox.info(), which is always synchronous --- do notawaitit).- Using
async withonBoxlite, or a plainwithonSimpleBox, raises a context-manager protocol error.
No resource quotas set, so one runaway session drags down the host
Whencpus / memory_mib are not passed, SimpleBox forwards the fields to
the underlying engine, which allocates a default. A production agent should set
cpus / memory_mib quotas explicitly per session for predictability and
cost control, and estimate total resource use against expected concurrency. See
Compute Resources.
The third volume element was a string instead of a bool
If a tool needs to mount a host directory (such as a code repository), the third element of a volume is the boolread_only (True = read-only / False =
read-write), not a string. Passing "ro" / "rw" raises:
volumes=[("/host/repo", "/work", True)] (read-only) or a
2-tuple (default read-write). This differs from the CLI’s
-v host:box:ro string syntax --- that belongs to the CLI parsing layer, while
the SDK API uses a bool. See Volumes.
Start fails: no hardware virtualization
BoxLite needs hardware virtualization to bring up the per-session microVM:- Linux: needs KVM (
/dev/kvmaccessible; on WSL2, KVM must be enabled and the user must be in thekvmgroup). - macOS: uses Apple Hypervisor.framework, no
/dev/kvmrequired. macOS Intel is not supported. - No-virtualization environments (some containers / CI):
start()fails and raises, but the process stays alive --- catch it withtry/exceptto degrade gracefully on CI without virtualization.

