Skip to main content

Vercel Eve Sandboxes

5 min read

Eve is Vercel's agent framework. It gives an agent a code-execution sandbox through a single agent/sandbox.ts file, and the provider behind that file is swappable.

@upstash/agentkit-eve ships an Upstash Box sandbox provider for it, UpstashSandbox. You use it exactly like Eve's built-in VercelSandbox, and your agent runs its code inside a Box. Egress is deny-all by default, setup is baked into a snapshot at build time, and each session gets its own box.


1. Start from an Eve project#

Scaffold one if you do not have it yet. This installs eve and an AI SDK provider for you.

Use eve 0.65.0 or later.


2. Install the packages#

@upstash/box (0.7.1 or later) is an optional peer dependency of the AgentKit package. You only need it because you are importing the sandbox provider.

Get a Box API key from the Upstash Console:

.env

The provider reads the key both when Eve prepares the sandbox environment (at eve build, see step 5) and at run time, so set it in both places. No Redis is involved.


3. Define the sandbox#

A sandbox file exports an environment and returns a sandbox from defineSandbox():

agent/sandbox.ts

The environment export is required: Eve prepares it at build time, before any session exists.

UpstashSandbox.environment(options) takes the @upstash/box BoxConfig. Whatever you would pass to Box.create({ ... }) you pass here: runtime, size, apiKey (defaults to UPSTASH_BOX_API_KEY), keepAlive, initCommand, env, git, skills, mcpServers, attachHeaders, timeout, and so on. There are no renamed knobs to keep in sync.

Three things differ from a raw Box.create:

  • networkPolicy is not accepted, because egress is governed per session (see the next step).
  • name is not accepted either, because every session gets its own box. Boxes are named eve-<session hash>-<random>, so you can trace them back to their session in the console.
  • Two AgentKit fields sit alongside the Box config: prepare (step 5) and baseSnapshot (heavy setup).

That is the whole setup. Run your agent and ask it to execute something:

Eve's built-in bash, read_file, write_file, glob, and grep tools now run inside the box.


4. Open egress per session#

The sandbox runs model-generated code, so egress is deny-all by default. Open it where you need it, when the session's box is opened:

agent/sandbox.ts

Pass "allow-all" when the agent genuinely needs the open internet, and nothing at all to keep the secure default. A tool can also change it mid-session with sandbox.setNetworkPolicy(...). Box enforces the policy on the box itself, so it survives the box being paused and resumed.

Warning

env passed to UpstashSandbox.environment({ env }) is readable by code running in the box. Do not put secrets there that the model should not see.

Brokering credentials#

Box network policies are plain domain and CIDR allow lists. Eve's per-domain firewall rules (transform header injection, forwardURL, match) have no Box equivalent, so passing them throws instead of quietly sending the request unauthenticated.

Use Box's attachHeaders instead. A proxy on the box injects the header at the firewall, so the secret never enters the box:

agent/sandbox.ts

5. Bake setup into the environment#

A prepare hook holds the setup every session should inherit. Eve runs it once per environment, not once per session, and the provider captures the result as a Box snapshot that every session's box is restored from.

agent/sandbox.ts

A box runs as the non-root boxuser, so system-wide installs need sudo -n. Without it apt-get exits 100 on the dpkg lock and preparation fails. Workspace-local installs such as npm install need no sudo. The network policy you set in prepare is not inherited by sessions.

The snapshot also carries Eve's managed files:

  • Files under agent/sandbox/workspace/ land in /workspace.
  • Your agent's skills land in $HOME/.agents/skills.

If there is nothing to bake (no workspace files, no skills, no prepare), no temporary box or snapshot is created.

Preparation runs at eve build, and under eve dev on the first sandbox access. Eve stores the snapshot id in the build output, so sessions in production restore from it directly. Changing prepare, the workspace files, the skills, or the environment options produces a new environment for new sessions, while existing sessions keep their box.

Note

Each build that has something to prepare creates a new snapshot. Box addresses snapshots by id, not by name, so old ones are not reused or removed automatically. Delete stale snapshots in the console or with Box.deleteSnapshots().

Heavy, slow-changing setup#

For things too heavy to rebuild on every build (browser binaries, ffmpeg, a full toolchain), build a Box snapshot yourself out of band and point baseSnapshot at it. prepare then layers on top of it, and with nothing to prepare, sessions restore from it directly.

Pass a snapshot id or a resolver, since Box addresses snapshots by id rather than by name. Returning undefined means no base snapshot.


6. Lifecycle#

Each Eve session owns one box, created the first time the session touches its sandbox and reused for the rest of the session: across turns, workflow steps, server restarts and redeploys.

  • sandbox.stop() pauses the box. The next command resumes it with its files intact.
  • When the server shuts down, open boxes are paused too.
  • sandbox.delete() deletes the box. The session's next sandbox access starts a fresh one from the environment's snapshot.

If a session's box no longer exists, for example because it was deleted in the console, the session fails with a clear error instead of silently getting an empty box and losing its files. Call sandbox.delete() to start fresh. Likewise, if the prepared snapshot has been deleted, starting a new session fails and asks you to rebuild or redeploy.

Boxes use Box's pause-based idle lifecycle by default (keepAlive: false): auto-paused when idle, resumed on the next command. Pass keepAlive: true only when you want an always-running box that you manage and delete yourself.

Commands run over Box's streaming exec sessions. stdout and stderr are kept separate, and when a turn is cancelled the running command is killed.

Note

Eve roots its tools at /workspace, while a Box session lives at /workspace/home. The provider rewrites paths and command text between the two automatically, so tools like glob and grep search the right directory.


Migrating from upstash()#

Eve 0.64 replaced sandbox backends with providers, so defineSandbox({ backend: upstash(...) }) from @upstash/agentkit-eve 0.12 and earlier no longer exists:

  • bootstrap becomes the environment's prepare.
  • onSession's use({ networkPolicy }) becomes environment.open({ networkPolicy }).
  • revalidationKey goes away: Eve now derives when to prepare again from the sandbox source and options.
  • The redis, templatePrefix, and enableTelemetry options are gone, because the snapshot id now lives in Eve's build output.
agent/sandbox.ts

Next steps#

The same package carries the rest of AgentKit for Eve: long-term memory, searchable chat history, RAG over Redis Search, a rate-limit gate for your channel's auth walk, and Redis-memoized tools.