Sandboxes
Configure sandbox infrastructure for EVE sessions and code execution
Sandbox providers supply execution infrastructure independently of installed tools. ChatJS uses the selected provider for code execution and, when supported, persistent EVE session files. Installing a sandbox provider does not expose a code-execution tool to the model.
EVE session sandboxes
The main agent declares its sandbox environment in agent/sandbox.ts. Account sessions register their sandbox lifecycle, and research subagents inherit the parent sandbox. Persistent providers support session files, process execution, resume, and cleanup.
| Built-in provider | Code-execution tools | Persistent EVE session files |
|---|---|---|
| Vercel Sandbox | Supported | Supported |
| Daytona | Supported | Not supported by the current adapter |
Ordinary chat can run without persistent sandbox support. ChatJS explicitly disables the EVE sandbox environment in that case, and requests requiring its filesystem fail. Ephemeral code execution and persistent session files are separate capabilities.
To install infrastructure without a model-facing tool:
bunx chat-js@alpha add --sandbox-provider vercel
See Code Execution for installing and using the tool.
Select a provider
Select the tool when creating an app:
npx chat-js@alpha create my-app --yes \
--code-execution-tool code-execution --sandbox-provider vercel
This installs the generic tool under chatjs/tools/code-execution/ and the selected provider under chatjs/providers/sandbox/. An external sandbox registry item URL is also accepted:
npx chat-js@alpha create my-app --yes \
--code-execution-tool code-execution --sandbox-provider https://example.com/r/my-sandbox.json
The fresh template includes only the selected implementation and dependencies. The CLI prints the selected item’s credential requirements. Vercel Sandbox needs VERCEL_OIDC_TOKEN or the team/project/token credentials described below.
For an existing app, use add. Replace an installed provider explicitly. Modified source requires --overwrite after review:
bunx chat-js@alpha add --sandbox-provider daytona --replace
To install infrastructure without exposing a model tool, use add --sandbox-provider vercel. To install both together, use add code-execution --sandbox-provider daytona. Replacing the provider leaves the tool unchanged. There is no enabled flag or central provider switch. Keep generated registrations intact and use add or sync to regenerate them. Drain existing sandbox resources before replacing the provider or rotating its credentials.
Saved-code execution requires a compatible executor and code documents. The planner resolves these dependencies and reuses an existing sandbox selection. If none exists, select one explicitly:
bunx chat-js@alpha add saved-code-execution --sandbox-provider daytona
Daytona credentials
To create an app using Daytona:
bunx chat-js@alpha create my-app --yes \
--code-execution-tool code-execution --sandbox-provider daytona
Configure your Daytona organization and its API key in .env.local:
DAYTONA_API_KEY=your_api_key
DAYTONA_ORGANIZATION_ID=your_organization_id
Run the generated environment check before startup. The descriptor declares both variables and the adapter rejects empty credentials before allocation. The returned sandbox organization must match the configured organization. This adapter uses Daytona Cloud at https://app.daytona.io/api and needs no Vercel sandbox credentials. It does not certify the rest of your hosting configuration.
Sandbox images
Select the image for each language with environment variables:
VERCEL_SANDBOX_IMAGE_PYTHON=vercel/sandbox/python:3.14
VERCEL_SANDBOX_IMAGE_JAVASCRIPT=vercel/sandbox/node:22
Vercel execution uses managed images. Python defaults to Python 3.14 on Ubuntu, and JavaScript defaults to Node.js 22 on Ubuntu. You can set either image variable to a Vercel Container Registry reference with the corresponding python3 and pip, or node, commands available. Legacy VERCEL_SANDBOX_RUNTIME* settings are no longer read.
Vercel Sandbox outside Vercel hosting
If you select Vercel Sandbox while hosting outside Vercel, you need to authenticate with an access token since VERCEL_OIDC_TOKEN is unavailable.
- Copy your Team ID from team settings
- Copy your Project ID from project settings
- Create a token in your Vercel account settings scoped to your team
- Set these environment variables:
VERCEL_TEAM_ID=team_xxx
VERCEL_PROJECT_ID=prj_xxx
VERCEL_TOKEN=your_token_here
The sandbox automatically uses these credentials when running outside Vercel infrastructure.
Provider contract
chatjs/providers/sandbox/provider.ts exports the selected provider factory, adapter.ts contains its SDK integration, and options.ts declares its identity and environment requirements. lib/sandbox/runtime.ts exposes getSandboxProvider() to consumers. @chat-js/sandboxes/provider defines the common command and provider interfaces. @chat-js/sandboxes/runtime provides withSandbox, which coordinates allocation, cancellation and confirmed cleanup with the consumer’s durable ownership store.
In this repository, contracts and lifecycle code live in packages/sandboxes, provider implementations in packages/registry/src/sandboxes/{vercel,daytona}, and the generic tool in packages/registry/src/tools/code-execution.
Third-party sandbox registry items use kind: "sandbox" metadata matching @chat-js/sandboxes/definition and install chatjs/providers/sandbox/provider.ts exporting createSandboxProvider. Version 1 requires Python and JavaScript commands, terminating cancellation and durable allocation cleanup. Capability metadata is a declaration, not evidence of live service behavior. Custom code-execution tools can separately implement the typed executor contract.
Lifecycle and accounting
Daytona execution has a five-minute application deadline and a ten-minute provider wall-clock TTL. Each sandbox is private and ephemeral. Cancellation requests deletion, including when cancellation happens while creation is still completing. Command output is combined into the text response. Python charts return structured data or a PNG. Arbitrary sandbox files are not persisted or downloaded into application storage.
Before allocation, the executor records a durable intent bound to the owner, session, tool call and provider scope. It confirms creation before running source and releases ownership only after provider deletion is confirmed. Cleanup failure retains the intent for a later conversation-deletion retry. Restarted execution refuses to allocate again for the same call until the previous intent is reconciled.
An uncertain create response remains an explicit reconciliation blocker. A single missing-resource response or elapsed TTL is not proof that an in-flight create can never complete. Operators must establish the allocation outcome before clearing its durable intent. This restriction also exists in the Vercel contract.
Daytona API-key authentication does not honor a separate organization override. Cleanup therefore binds to a non-secret key fingerprint as well as the configured organization. Keep the original credentials until all resources are drained. Replacing the provider or key with outstanding intents fails closed and requires restoring the original provider scope or performing verified reconciliation.
The shared executor records a fixed $0.05 usage cost for a completed built-in execution, independently of the provider’s invoice. It records zero application cost for infrastructure failure and records the completed-execution cost only after output validation and confirmed cleanup. The optional Credits plugin applies balance checks and debits. Core retains usage evidence without a billing adapter. Native EVE cancellation and settlement retain their existing receipt behavior. Shared code wrappers can report user-code errors as completed executions. Provider compute costs may still accrue on failures, cancellation and uncertain creation.
Provider evaluation and validation
Daytona was selected because its TypeScript SDK supports named allocation lookup and deletion confirmation. Its sandbox API also exposes organization identity, command execution, and wall-clock TTL. E2B metadata supports finding sandboxes by metadata, but adopting it would require a separate reconciliation design around provider-generated identities. Both are real providers. Neither provider’s documentation alone certifies this installation.
The evaluation used the existing Vercel caller contract and provider documentation, not a live vendor benchmark:
| Requirement | Daytona, selected | E2B, evaluated |
|---|---|---|
| JavaScript and Python | SDK supports both, adapter runs the shared Node/Python wrappers | Both supported by its code interpreter |
| Deadline and cancellation | Command timeout plus wall-clock TTL, cancellation deletes the resource | Configurable sandbox timeout and explicit kill, pause behavior must be excluded from erasure |
| Output and files | Command output and sandbox filesystem, shared wrappers return charts | Code output and file read/write APIs, would need ChatJS output conversion |
| Identity before creation | Caller-selected name with returned organization identity | Provider-generated ID plus metadata, requires metadata reconciliation |
| Cleanup after restart | Resolve the durable name, delete and confirm absence | List running/paused resources and kill, additional inventory/absence proof needed |
| Usage accounting | One native ChatJS receipt after confirmed cleanup | Would need the same application receipt wrapper, separate from vendor billing |
E2B references: languages, lifecycle, inventory, and file access. Daytona references: commands and sandbox lifecycle. The choice favors the existing named-allocation contract. It is not a claim that E2B cannot implement it.
The implementation pins @daytona/sdk to 0.220.0. Offline tests cover allocation ordering, identity mismatch, cancellation, cleanup failure, output quoting, and restart cleanup. Live acceptance requires a Daytona account with sandbox create, read, command and delete permissions, both environment variables above, and the application’s native EVE/database configuration. Local live verification on October 5, 2026 passed JavaScript output, Python PNG charts, cancellation with deletion, and cleanup from a fresh process. The native executor also recorded a single $0.05 receipt and released durable ownership against isolated PostgreSQL; retry refused duplicate allocation and repeated deletion succeeded. These checks used the real Daytona service, but do not certify a hosted deployment, scheduled retention, or full browser-to-worker execution.