> ## Documentation Index
> Fetch the complete documentation index at: https://upstash-dx-3081-agentkit-tanstack-ai-backends.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Vercel Eve Sandboxes

[Eve](https://eve.dev) 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`](https://www.npmjs.com/package/@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.

```bash theme={null}
npx eve@latest init my-agent
# or, to start with a Next.js app:
npx eve@latest init my-agent --channel-web-nextjs
```

Use eve `0.65.0` or later.

***

## 2. Install the packages

```bash theme={null}
npm install @upstash/agentkit-eve @upstash/box
```

`@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](https://console.upstash.com/box):

```bash title=".env" theme={null}
UPSTASH_BOX_API_KEY=box_xxxxxxxxxxxxxxxxxxxxxxxx
```

The provider reads the key both when Eve prepares the sandbox environment (at `eve build`, see [step 5](#5-bake-setup-into-the-environment)) 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()`:

```typescript title="agent/sandbox.ts" theme={null}
import { defineSandbox } from "eve/sandbox";
import { UpstashSandbox } from "@upstash/agentkit-eve/sandbox";

export const environment = UpstashSandbox.environment({ runtime: "node", size: "medium" });

export default defineSandbox(() => environment.open());
```

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](#5-bake-setup-into-the-environment)) and `baseSnapshot` ([heavy setup](#heavy-slow-changing-setup)).

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

```bash theme={null}
npx eve dev
```

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](/box/overall/network-policy) by default. Open it where you need it, when the session's box is opened:

```typescript title="agent/sandbox.ts" theme={null}
export default defineSandbox(() =>
  environment.open({ networkPolicy: { allow: ["registry.npmjs.org", "api.github.com"] } }),
);
```

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.
</Warning>

### 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`](/box/overall/attach-headers) instead. A proxy on the box injects the header at the firewall, so the secret never enters the box:

```typescript title="agent/sandbox.ts" theme={null}
export const environment = UpstashSandbox.environment({
  runtime: "node",
  attachHeaders: { "api.example.com": { Authorization: "Bearer ..." } },
});

export default defineSandbox(() =>
  environment.open({ networkPolicy: { allow: ["api.example.com"] } }),
);
```

***

## 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](/box/overall/snapshots) that every session's box is restored from.

```typescript title="agent/sandbox.ts" theme={null}
export const environment = UpstashSandbox.environment({
  runtime: "node",
  size: "medium",
  async prepare(sandbox) {
    await sandbox.setNetworkPolicy("allow-all"); // prepare starts deny-all too
    const result = await sandbox.run({ command: "sudo -n apt-get install -y jq" });
    if (result.exitCode !== 0) throw new Error(result.stderr);
  },
});

export default defineSandbox(() => environment.open());
```

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()`.
</Note>

### 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.

```typescript theme={null}
UpstashSandbox.environment({
  runtime: "node",
  baseSnapshot: async () => (await redis.get<string>("toolchain-snapshot")) ?? undefined,
});
```

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`](/box/overall/keep-alive) 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.
</Note>

***

## 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.

```typescript title="agent/sandbox.ts" theme={null}
// before
export default defineSandbox({
  backend: upstash({ runtime: "node" }),
  async bootstrap({ use }) {
    const sandbox = await use({ networkPolicy: "allow-all" });
    await sandbox.run({ command: "sudo -n apt-get install -y jq" });
  },
  async onSession({ use }) {
    await use();
  },
});

// after
export const environment = UpstashSandbox.environment({
  runtime: "node",
  async prepare(sandbox) {
    await sandbox.setNetworkPolicy("allow-all");
    await sandbox.run({ command: "sudo -n apt-get install -y jq" });
  },
});

export default defineSandbox(() => environment.open());
```

***

## 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.

* [AgentKit for Vercel Eve](/redis/sdks/agentkit/eve) for the full package reference.
* [Network policies](/box/overall/network-policy) for what Box's allow lists can express.
* [Snapshots](/box/overall/snapshots) for building and restoring the boxes behind a sandbox environment.


## Related topics

- [Memory, Chat History, RAG, Rate Limiting & Sandboxes for the Vercel Eve Agent Framework](/redis/sdks/agentkit/eve.md)
- [Vercel](/workflow/troubleshooting/vercel.md)
- [Python on Vercel](/qstash/quickstarts/python-vercel.md)
- [Vercel Python Runtime](/redis/quickstarts/vercel-python-runtime.md)
- [Vercel AI SDK](/workflow/integrations/aisdk.md)
