npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tangle-network/sandbox

v0.0.1

Published

Client SDK for the Tangle Sandbox platform - build AI agent applications with dev containers

Readme

@tangle-network/sandbox

TypeScript SDK for the Tangle Sandbox platform. Create isolated dev containers, run AI agents, and build automation workflows.

CLI

There is a separate CLI package at products/sandbox/cli published as @tangle-network/sandbox-cli.

  • Current auth support in the CLI is API-key-only
  • Browser OAuth/session auth exists in the sandbox web/api product, but it is not wired into the CLI yet
  • See ../cli/README.md for the current CLI surface
  • See ../cli/CHECKLIST.md for the parity and auth spec

Installation

npm install @tangle-network/sandbox
# or
pnpm add @tangle-network/sandbox
# or
yarn add @tangle-network/sandbox

Quick Start

import { Sandbox } from "@tangle-network/sandbox";

// Initialize the client
const client = new Sandbox({
  apiKey: "sk_sandbox_...",
  baseUrl: "https://your-sandbox-api.example.com",
});

// Create a sandbox
const box = await client.create({
  name: "my-project",
  image: "node:20",
});

// Execute commands
const result = await box.exec("npm install && npm test");
console.log(result.stdout);

// Run an AI agent task
const task = await box.task("Fix any failing tests and commit the changes");
console.log(task.response);

// Clean up
await box.delete();

Features

  • Sandbox Management - Create, list, stop, resume, and delete sandboxes
  • Command Execution - Run shell commands in isolated containers
  • AI Agent Tasks - Multi-turn agent execution with automatic tool use
  • Snapshots - Save and restore sandbox state
  • BYOS3 - Bring your own S3 storage for snapshots
  • Batch Execution - Run tasks across multiple sandboxes in parallel
  • Event Streaming - Real-time SSE streams for agent events
  • Collaboration Foundations - Token issuance and document identity helpers for collaborative editing

Collaboration Foundations

The SDK now includes the first collaboration primitives for product backends:

  • collaboration token issuance from @tangle-network/sandbox/auth
  • stable document identity helpers from @tangle-network/sandbox/collaboration
  • a collaboration API client for bootstrap / token refresh / snapshot calls
  • a headless file bridge for syncing document adapters with sandbox files

Example:

import {
  buildCollaborationDocumentId,
} from "@tangle-network/sandbox/collaboration";
import { ProductTokenIssuer } from "@tangle-network/sandbox/auth";

const issuer = new ProductTokenIssuer({
  productId: "gtm-agent",
  signingSecret: process.env.ORCHESTRATOR_SIGNING_SECRET!,
});

const documentId = buildCollaborationDocumentId({
  workspaceId: "ws_123",
  relativePath: "system/operating-system.md",
});

const { token, expiresAt } = issuer.issueCollaboration({
  userId: "user_123",
  sessionId: "sess_456",
  projectId: "ws_123",
  documentId,
  access: "write",
});

Bootstrap and snapshot helpers:

import { CollaborationClient } from "@tangle-network/sandbox/collaboration";

const collab = new CollaborationClient({
  baseUrl: "https://app.example.com",
  headers: () => ({
    Authorization: `Bearer ${sessionToken}`,
  }),
});

const bootstrap = await collab.bootstrap({
  workspaceId: "ws_123",
  relativePath: "system/operating-system.md",
});

The bridge and client are SDK-side primitives. Product/backend endpoints and CRDT runtime integration still need to be wired by the application.

Core Concepts

Sandboxes

A sandbox is an isolated dev container with:

  • A sidecar API for programmatic control
  • Optional SSH access
  • Optional web terminal
  • Persistent storage with snapshots
const box = await client.create({
  name: "my-sandbox",
  image: "python:3.12",
  env: { DEBUG: "true" },
  sshEnabled: true,
  maxLifetimeSeconds: 7200,  // 2 hours
  idleTimeoutSeconds: 1800,  // 30 min idle timeout
  resources: {
    cpuCores: 2,
    memoryMB: 4096,
    diskGB: 20,
  },
});

Status Lifecycle

pending -> provisioning -> running -> stopped -> deleted
                              |
                              v
                           failed

API Reference

Client

import { Sandbox } from "@tangle-network/sandbox";

const client = new Sandbox({
  apiKey: "sk_sandbox_...",
  baseUrl: "https://your-sandbox-api.example.com", // required
  timeoutMs: 30000, // optional
});

client.create(options?)

Create a new sandbox.

const box = await client.create({
  name: "my-project",
  image: "node:20",              // or "typescript" for pre-built image
  agentIdentifier: "my-agent",   // agent to run
  env: { NODE_ENV: "development" },
  sshEnabled: true,
  sshPublicKey: "ssh-ed25519 AAAA...",
  webTerminalEnabled: true,
  maxLifetimeSeconds: 3600,
  idleTimeoutSeconds: 900,
  resources: {
    cpuCores: 2,
    memoryMB: 4096,
    diskGB: 20,
  },
  metadata: { team: "platform" },
  // BYOS3: Customer-provided storage
  storage: {
    type: "s3",
    bucket: "my-snapshots",
    region: "us-east-1",
    credentials: {
      accessKeyId: "AKIA...",
      secretAccessKey: "...",
    },
  },
  fromSnapshot: "snap_abc123",   // restore from snapshot
});

client.list(options?)

List all sandboxes.

const sandboxes = await client.list({
  status: "running",        // filter by status
  limit: 10,
  offset: 0,
});

client.get(id)

Get a sandbox by ID.

const box = await client.get("sandbox_abc123");
if (box) {
  console.log(box.status);
}

client.usage()

Get account usage information.

const usage = await client.usage();
console.log(`Active: ${usage.activeSandboxes}`);
console.log(`Compute: ${usage.computeMinutes} minutes`);

client.runBatch(tasks, options?)

Run tasks across multiple sandboxes in parallel.

const result = await client.runBatch([
  { id: "task-1", message: "Analyze code quality" },
  { id: "task-2", message: "Run security scan" },
  { id: "task-3", message: "Generate documentation" },
], {
  timeoutMs: 300000,
  scalingMode: "balanced", // "fastest" | "balanced" | "cheapest"
});

console.log(`Success rate: ${result.successRate}%`);

Sandbox Instance

After creating or retrieving a sandbox, you get a SandboxInstance with these methods:

box.exec(command, options?)

Execute a shell command.

const result = await box.exec("npm install", {
  cwd: "/workspace",
  env: { CI: "true" },
  timeoutMs: 60000,
});

console.log(result.exitCode);  // 0
console.log(result.stdout);
console.log(result.stderr);

box.prompt(message, options?)

Send a single prompt to the AI agent.

const result = await box.prompt("What files are in this project?", {
  sessionId: "session_123",  // for conversation continuity
  model: "anthropic/claude-sonnet-4-20250514",
  timeoutMs: 120000,
});

console.log(result.response);
console.log(result.usage);  // { inputTokens, outputTokens }

Backend Selection

Each sandbox runs one AI backend. Pass backend.type to choose it:

| Type | Runtime | When to use | |------|---------|-------------| | opencode | OpenCode | Default. Multi-provider, profile system, MCP support | | claude-code | Claude Code | Anthropic-native. Needs ANTHROPIC_API_KEY | | codex | Codex CLI | OpenAI-native. Needs OPENAI_API_KEY | | amp | AMP | Sourcegraph AMP agent | | factory-droids | Factory | Factory Droid agent |

// Use Claude Code backend
await box.prompt("Fix the auth bug", {
  backend: { type: "claude-code" },
});

// Use Codex with a named profile
await box.prompt("Audit this repo", {
  backend: { type: "codex", profile: "browser-codex-fast" },
});

// Use OpenCode with an inline profile
await box.prompt("Audit this repo", {
  backend: {
    type: "opencode",
    profile: {
      name: "security-auditor",
      prompt: {
        systemPrompt: "Focus on authorization and sandbox boundary mistakes.",
      },
      tools: { bash: true },
      permissions: { bash: "allow" },
    },
  },
});

// BYOK (Bring Your Own Key)
await box.prompt("Analyze this", {
  backend: {
    type: "opencode",
    model: {
      provider: "anthropic",
      model: "claude-sonnet-4-20250514",
      apiKey: process.env.MY_ANTHROPIC_KEY,
    },
  },
});

The SDK generates the sidecar-native wire format automatically from backend.profile.

box.task(message, options?)

Run a multi-turn agent task. The agent keeps working until completion.

const result = await box.task("Set up a REST API with authentication", {
  maxTurns: 20,      // limit turns (0 = unlimited)
  sessionId: "...",  // continue previous session
});

console.log(result.turnsUsed);
console.log(result.response);

box.streamPrompt(message, options?)

Stream agent events in real-time.

for await (const event of box.streamPrompt("Explain this codebase")) {
  switch (event.type) {
    case "message.part.updated": {
      const part = event.data.part as { type?: string; text?: string };
      if (part.type === "text" && event.data.delta) {
        process.stdout.write(String(event.data.delta));
      }
      break;
    }
    case "result":
      console.log("\nFinal:", event.data.finalText);
      break;
    case "done":
      console.log("\nComplete!");
      break;
  }
}

box.streamTask(message, options?)

Stream a multi-turn task with real-time events.

for await (const event of box.streamTask("Build a CLI tool")) {
  // Handle events...
}

box.direct()

Create an explicit advanced direct-runtime view of the sandbox.

const directBox = box.direct();
const result = await directBox.exec("npm test");

box.events(options?)

Subscribe to sandbox lifecycle events.

for await (const event of box.events({ signal: controller.signal })) {
  console.log(`Event: ${event.type}`, event.data);
}

Snapshots

box.snapshot(options?)

Create a snapshot of the sandbox state.

const snapshot = await box.snapshot({
  tags: ["v1.0", "stable"],
  paths: ["/workspace"],  // specific paths (default: all)
});

console.log(snapshot.snapshotId);
console.log(snapshot.sizeBytes);

box.listSnapshots()

List all snapshots for this sandbox.

const snapshots = await box.listSnapshots();
for (const snap of snapshots) {
  console.log(`${snap.snapshotId}: ${snap.createdAt}`);
}

BYOS3 (Bring Your Own S3)

Store snapshots in your own S3-compatible storage. Supports AWS S3, Google Cloud Storage, and Cloudflare R2.

Creating a sandbox with BYOS3

const box = await client.create({
  name: "my-sandbox",
  storage: {
    type: "s3",  // "s3" | "gcs" | "r2"
    bucket: "my-snapshots",
    region: "us-east-1",
    endpoint: "https://s3.us-east-1.amazonaws.com",  // optional
    credentials: {
      accessKeyId: "AKIA...",
      secretAccessKey: "...",
    },
    prefix: "sandbox-snapshots/",  // optional path prefix
  },
  fromSnapshot: "snap_abc123",  // restore from your storage
});

Snapshots with BYOS3

When storage is configured, snapshots are written directly to your bucket:

// Create snapshot to your S3
const snap = await box.snapshot({
  tags: ["production"],
  storage: {
    type: "s3",
    bucket: "my-snapshots",
    credentials: { accessKeyId: "...", secretAccessKey: "..." },
  },
});

// List snapshots from your S3
const snapshots = await box.listSnapshots({
  type: "s3",
  bucket: "my-snapshots",
  credentials: { ... },
});

// Restore from your S3
await box.restoreFromStorage({
  type: "s3",
  bucket: "my-snapshots",
  credentials: { ... },
});

Runtime Routing

By default, SDK runtime calls like exec(), prompt(), task(), file ops, git, and process management go through the Sandbox API, which proxies to orchestrator and the correct sidecar for the authenticated user.

Runtime agent calls can pass a named backend profile or an inline provider-neutral profile object:

const result = await box.prompt("Audit the authentication flow", {
  backend: {
    profile: {
      name: "security-auditor",
      prompt: {
        systemPrompt: "You are a senior application security auditor.",
        instructions: ["Prioritize authz, tenancy, and secret handling."],
      },
      tools: { bash: true },
      permissions: { bash: "allow" },
    },
  },
});

Direct Sidecar Access

For advanced use cases, use box.direct() to make runtime calls directly against the sidecar while keeping normal lifecycle methods on the API client:

const directBox = box.direct();
const result = await directBox.exec("npm test");

This is the recommended advanced path for power users who want sidecar-level runtime access without re-implementing auth/header plumbing themselves.

If you need raw low-level access, you can still communicate directly with the sidecar API using the provided auth token:

const box = await client.create({ name: "my-sandbox" });

// Wait for running status
await box.waitForRunning();

// Get connection info
const { sidecarUrl, authToken } = box.connection;

// Make direct API calls
const response = await fetch(`${sidecarUrl}/snapshots`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${authToken}`,
  },
  body: JSON.stringify({
    projectId: box.id,
    storage: myS3Config,
    tags: ["manual"],
  }),
});

Lifecycle Methods

// Stop (preserves state)
await box.stop();

// Resume
await box.resume();

// Delete (destroys everything)
await box.delete();

// Refresh status from API
await box.refresh();

// Wait for specific status
await box.waitForRunning({ timeoutMs: 60000 });

Properties

box.id              // Unique identifier
box.name            // Human-readable name
box.status          // "pending" | "provisioning" | "running" | "stopped" | "failed"
box.connection      // raw direct connection info for advanced use
box.metadata        // Custom metadata
box.createdAt       // Date
box.startedAt       // Date | undefined
box.lastActivityAt  // Date | undefined
box.expiresAt       // Date | undefined
box.error           // Error message if failed

Error Handling

import {
  AuthError,
  NetworkError,
  NotFoundError,
  QuotaError,
  StateError,
  TimeoutError,
  ValidationError,
} from "@tangle-network/sandbox";

try {
  await box.exec("npm test");
} catch (err) {
  if (err instanceof TimeoutError) {
    console.log("Command timed out");
  } else if (err instanceof StateError) {
    console.log(`Invalid state: ${err.currentState}`);
  } else if (err instanceof NetworkError) {
    console.log("Connection failed");
  }
}

TypeScript

Full TypeScript support with exported types:

import type {
  SandboxClientConfig,
  CreateSandboxOptions,
  SandboxInfo,
  SandboxStatus,
  SandboxConnection,
  ExecResult,
  ExecOptions,
  PromptResult,
  PromptOptions,
  TaskResult,
  TaskOptions,
  SnapshotResult,
  SnapshotOptions,
  SnapshotInfo,
  StorageConfig,
  BatchTask,
  BatchResult,
  BatchOptions,
  UsageInfo,
} from "@tangle-network/sandbox";

Examples

See the examples directory for complete runnable examples:

  • basic-usage.ts - Creating sandboxes and running commands
  • agent-tasks.ts - Multi-turn AI agent execution
  • streaming.ts - Real-time event streaming
  • snapshots.ts - Creating and restoring snapshots
  • byos3.ts - Using customer-provided S3 storage
  • batch.ts - Parallel task execution

License

MIT