JSPM

  • Created
  • Published
  • Downloads 1248
  • Score
    100M100P100Q136568F
  • License MIT

Upstash Box SDK - TypeScript client for async and parallel AI coding agents

Package Exports

  • @upstash/box

Readme

@upstash/box

TypeScript SDK for Upstash Box — create sandboxed AI coding agents with streaming, structured output, file I/O, git operations, and snapshots.

Installation

npm install @upstash/box

Quick start

import { Box, Runtime, ClaudeCode } from "@upstash/box";

const box = await Box.create({
  runtime: Runtime.Node,
  agent: {
    model: ClaudeCode.Sonnet_4_5,
    apiKey: process.env.CLAUDE_KEY!,
  },
});

const run = await box.agent.run({
  prompt: "Create a hello world Express server",
  onStream: (chunk) => process.stdout.write(chunk),
});

console.log(await run.result());
await box.delete();

Authentication

Pass apiKey in the config or set the UPSTASH_BOX_API_KEY environment variable.

API

Static methods

Box.create(config: BoxConfig): Promise<Box>

Create a new sandboxed box.

const box = await Box.create({
  apiKey: "abx_...",         // or set UPSTASH_BOX_API_KEY
  runtime: Runtime.Node,     // node, python, golang, ruby, rust
  agent: {
    model: ClaudeCode.Sonnet_4_5,
    apiKey: process.env.CLAUDE_KEY!,
  },
  git: { token: process.env.GITHUB_TOKEN! },
  env: { NODE_ENV: "production" },
  timeout: 600000,
  debug: false,
});

Box.get(boxId: string, options?: BoxGetOptions): Promise<Box>

Reconnect to an existing box by ID.

const box = await Box.get("box_abc123");

Box.list(options?: ListOptions): Promise<BoxData[]>

List all boxes for the authenticated user.

const boxes = await Box.list();

Box.fromSnapshot(snapshotId: string, config: BoxConfig): Promise<Box>

Create a new box from a saved snapshot.

const box = await Box.fromSnapshot("snap_abc123", {
  agent: { model: ClaudeCode.Sonnet_4_5, apiKey: process.env.CLAUDE_KEY! },
});

Agent

box.agent.run(options: RunOptions): Promise<Run>

Run the AI agent with a prompt. Supports streaming, structured output with Zod schemas, timeouts, retries, tool use callbacks, and webhooks.

// Streaming
const run = await box.agent.run({
  prompt: "Fix the bug in auth.ts",
  onStream: (chunk) => process.stdout.write(chunk),
});

// Structured output
import { z } from "zod";

const schema = z.object({
  name: z.string(),
  score: z.number(),
});

const run = await box.agent.run({
  prompt: "Analyze this candidate",
  responseSchema: schema,
});
const result = await run.result(); // typed as { name: string, score: number }

box.exec(command: string): Promise<Run>

Execute a shell command in the box.

const run = await box.exec("node index.js");
console.log(await run.result());

Files

await box.files.write({ path: "hello.txt", content: "Hello!" });
const content = await box.files.read("hello.txt");
const entries = await box.files.list(".");
await box.files.upload([{ path: "./local.txt", destination: "remote.txt" }]);
await box.files.download({ path: "output/" });

Git

await box.git.clone({ repo: "https://github.com/user/repo", branch: "main" });
const diff = await box.git.diff();
const status = await box.git.status();
await box.git.commit({ message: "feat: add feature" });
await box.git.push({ branch: "main" });
const pr = await box.git.createPR({ title: "New feature", body: "Description" });

Lifecycle

await box.stop();            // Pause (preserves state)
await box.start();           // Resume
await box.delete();          // Permanent delete
const { status } = await box.getStatus();

Snapshots

const snapshot = await box.snapshot({ name: "checkpoint-1" });
const snapshots = await box.listSnapshots();
await box.deleteSnapshot(snapshot.id);

Run object

Every agent.run() and exec() call returns a Run object:

const run = await box.agent.run({ prompt: "..." });

run.id;                      // Run ID
await run.result();          // Final output (typed if schema provided)
await run.status();          // "running" | "completed" | "failed" | "cancelled"
await run.cost();            // { tokens, computeMs, totalUsd }
await run.cancel();          // Abort
await run.logs();            // Filtered log entries

for await (const chunk of run.stream()) {
  process.stdout.write(chunk);
}

Models

Claude Code

Enum Value
ClaudeCode.Opus_4_5 claude/opus_4_5
ClaudeCode.Opus_4_6 claude/opus_4_6
ClaudeCode.Sonnet_4 claude/sonnet_4
ClaudeCode.Sonnet_4_5 claude/sonnet_4_5
ClaudeCode.Haiku_4_5 claude/haiku_4_5

OpenAI Codex

Enum Value
OpenAICodex.GPT_5_3_Codex openai/gpt-5.3-codex
OpenAICodex.GPT_5_3_Codex_Spark openai/gpt-5.3-codex-spark
OpenAICodex.GPT_5_2_Codex openai/gpt-5.2-codex
OpenAICodex.GPT_5_1_Codex_Max openai/gpt-5.1-codex-max

Runtimes

Enum Value
Runtime.Node node
Runtime.Python python
Runtime.Golang golang
Runtime.Ruby ruby
Runtime.Rust rust

Examples

See the examples/ directory for complete working examples:

  • basic.ts — Create a box, run an agent, read output
  • streaming.ts — Parallel boxes with structured output (Zod)
  • file-upload.ts — Upload local files into the box
  • git-pr.ts — Clone a repo, make changes, create a PR
  • snapshot-restore.ts — Save and restore workspace state
  • webhook.ts — Fire-and-forget with webhook callbacks
  • multi-runtime.ts — Run across different runtimes
  • mcp-skills.ts — Attach MCP servers to a box

License

MIT