---
title: "Letting an Agent Run Shell Commands Safely with Vercel AI SDK v7 Sandboxes"
description: "I built a dependency-audit agent that runs npm commands on real projects. The new experimental sandbox support in Vercel AI SDK v7 is what made me comfortable shipping it."
image: "https://foundrysoft.co/api/og?type=article&title=Letting+an+Agent+Run+Shell+Commands+Safely+with+Vercel+AI+SDK+v7+Sandboxes&cat=AI+Engineering&rt=8+min+read&au=Varun+Raj+Manoharan&dt=2026-07-13"
url: "https://foundrysoft.co/blog/vercel-ai-sdk-v7-sandboxed-command-execution"
---

AI Engineering 2026-07-13 8 min read

# Letting an Agent Run Shell Commands Safely with Vercel AI SDK v7 Sandboxes

I built a dependency-audit agent that runs npm commands on real projects. The new experimental sandbox support in Vercel AI SDK v7 is what made me comfortable shipping it.

![Varun Raj Manoharan](https://foundrysoft.co/images/about/founder.webp)

Varun Raj Manoharan

Vercel AI SDK v7 Sandboxes Security TypeScript

The most useful agents I have built all share one trait: they run commands. Checking whether a dependency upgrade breaks the build, reproducing a bug report, running a linter over a branch. The moment an agent can execute shell commands, it becomes genuinely useful. It also becomes genuinely dangerous, because the model decides what those commands are.

Until now I solved this with duct tape. Every project had its own bespoke wrapper around E2B or a Docker container, and every tool I wrote was welded to that specific wrapper. Vercel AI SDK v7 ships a first-class answer: an `Experimental_SandboxSession` abstraction that you pass into `generateText`, `streamText`, or a `ToolLoopAgent` call. Tools are written against the interface, not the provider, so the same tool runs against a local session in dev and a real isolation provider in production.

I tested it by building a dependency-audit agent. You point it at a repository, it runs `npm audit` and the test suite, tries the upgrade, and reports what actually broke.

### Writing a sandbox-aware tool

The key change in v7 is that the sandbox arrives inside the tool's execution options, right next to `abortSignal`. The tool never imports a sandbox provider. It just delegates the risky part:

TypeScript

Copy

```typescript
import { generateText, tool } from 'ai';
import { z } from 'zod';

const runCommand = tool({
  description: 'Run a shell command in the project workspace',
  inputSchema: z.object({
    command: z.string(),
    workingDirectory: z.string().optional(),
  }),
  execute: async (
    { command, workingDirectory },
    { abortSignal, experimental_sandbox },
  ) => {
    if (!experimental_sandbox) {
      throw new Error('Sandbox is not available');
    }
    return experimental_sandbox.run({
      command,
      workingDirectory,
      env: { CI: 'true' },
      abortSignal,
    });
  },
});
```

Two details here matter more than they look. Forwarding `abortSignal` means that when the overall generation is aborted or times out, the sandbox can actually kill the running process instead of leaving a zombie `npm install` behind. And `workingDirectory` lets one sandbox session serve multiple repos without the tool caring where the default working directory is.

Then you attach a sandbox at the call site:

TypeScript

Copy

```typescript
const result = await generateText({
  model: 'anthropic/claude-sonnet-4.5',
  prompt: 'Upgrade next to the latest minor version and tell me if the tests still pass.',
  tools: { runCommand },
  experimental_sandbox: sandbox, // your Experimental_SandboxSession
});
```

### The part everyone will get wrong

The docs are unusually blunt about this, and they are right to be: the sandbox interface is a contract, not a security boundary. Your tool code still runs wherever your app runs. Only what you explicitly delegate through `experimental_sandbox.run(...)` executes in the sandbox environment.

That means a local implementation backed by `child_process.exec` with a working directory is fine for development and worthless for isolation. A model-generated `rm -rf ~` does not respect your working directory. For anything where the model composes the command from user input, you want a real provider (Vercel Sandbox, a Firecracker microVM, a container) behind the interface.

### Layering timeouts and approvals on top

What sold me on doing this in v7 rather than keeping my own wrapper is how the sandbox composes with the rest of the release. Commands hang. Test suites deadlock. v7's granular timeout config catches all of it without custom plumbing:

TypeScript

Copy

```typescript
timeout: {
  totalMs: 300_000,
  toolMs: 60_000,
  tools: { runCommand: 180_000 }, // npm install is slow, give it more
},
```

When a timeout fires, the abort signal we forwarded earlier propagates into the sandbox and the command dies with the step. And for the commands that scare me, I flagged the tool to require approval, so the agent pauses and shows me the exact command string before anything executes. Sandbox for containment, timeouts for runaways, approvals for judgment calls. Three separate guardrails, all native.

### Why this matters

My audit agent found a transitive vulnerability, ran the upgrade, watched two snapshot tests fail, and reported the diff, all inside an isolated session I could throw away afterwards. The interesting part is not that this is possible. It was always possible with enough glue code. The interesting part is that my tools no longer know which sandbox they run in, which means I can finally reuse them across projects and swap providers when pricing or cold-start times change.

It is experimental, and the API surface can shift in patch releases, so pin your version. But the shape of it is correct, and I have already deleted my wrapper.

#### Related reading

[MCP Went Stateless: Migrating Your Server to the 2026-07-28 Spec

The 2026-07-28 MCP revision removes sessions, the initialize handshake, and server-initiated requests. Here's what actually breaks in your server, the new wire format, the requestState and MRTR patterns that replace sessions, and the SDK v2 migration path.

MCP Model Context Protocol AI Agents

](https://foundrysoft.co/blog/mcp-stateless-spec-migration)[We Open-Sourced an AI Agent for Coverage Citations: And Broke It Twice

agent-for-insurance is an open-source drafting aid that will not state a coverage conclusion without citing your policy's own text. Here's how it works, and the two parsing bugs that taught us why that rule has to be enforced in code, not prose.

Open Source AI Agents Insurance

](https://foundrysoft.co/blog/open-source-ai-agent-insurance-coverage-citations)[We Open-Sourced an AI Agent That Catches the Markup/Margin Error Costing Contractors Money

agent-for-field-service is a free, self-hosted AI copilot for HVAC, plumbing, electrical, and roofing contractors that prices jobs to a real margin instead of a markup that only looks like one.

Open Source AI Agents eve

](https://foundrysoft.co/blog/open-source-ai-agent-contractor-quoting-margin)

#### Next Article

[

Building a Real-Time Voice Agent with Vercel AI SDK and LiveKit

](https://foundrysoft.co/blog/vercel-ai-sdk-livekit-voice-agent)

Available for new projects

## Let's build something great.

Have a project in mind? We are an elite software and AI development studio ready to bring your ideas to production. Let's talk about your roadmap.

Start a Project [See our work](https://foundrysoft.co/work)

```json
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "FoundrySoft",
  "url": "https://foundrysoft.co",
  "logo": "https://foundrysoft.co/logo.svg",
  "description": "FoundrySoft builds production-grade software and AI systems for US companies, from an India-based team of senior engineers.",
  "sameAs": [
    "https://github.com/foundrysofthq",
    "https://www.linkedin.com/company/foundrysoft",
    "https://www.instagram.com/foundrysoft/"
  ]
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "FoundrySoft",
  "url": "https://foundrysoft.co"
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "headline": "Letting an Agent Run Shell Commands Safely with Vercel AI SDK v7 Sandboxes",
  "description": "I built a dependency-audit agent that runs npm commands on real projects. The new experimental sandbox support in Vercel AI SDK v7 is what made me comfortable shipping it.",
  "url": "https://foundrysoft.co/blog/vercel-ai-sdk-v7-sandboxed-command-execution",
  "mainEntityOfPage": "https://foundrysoft.co/blog/vercel-ai-sdk-v7-sandboxed-command-execution",
  "image": [
    "https://foundrysoft.co/api/og?type=article&title=Letting+an+Agent+Run+Shell+Commands+Safely+with+Vercel+AI+SDK+v7+Sandboxes&cat=AI+Engineering&rt=8+min+read&au=Varun+Raj+Manoharan&dt=2026-07-13"
  ],
  "datePublished": "2026-07-13",
  "dateModified": "2026-07-13",
  "keywords": "Vercel, AI, SDK v7, Sandboxes, Security, TypeScript",
  "author": {
    "@type": "Person",
    "name": "Varun Raj Manoharan"
  },
  "publisher": {
    "@type": "Organization",
    "name": "FoundrySoft",
    "logo": {
      "@type": "ImageObject",
      "url": "https://foundrysoft.co/logo.svg"
    }
  }
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://foundrysoft.co/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Blog",
      "item": "https://foundrysoft.co/blog"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Letting an Agent Run Shell Commands Safely with Vercel AI SDK v7 Sandboxes",
      "item": "https://foundrysoft.co/blog/vercel-ai-sdk-v7-sandboxed-command-execution"
    }
  ]
}
```
