npm package: @syntera-ai/sandbox
Description: Syntera Sandbox SDK — Provider-based sandbox management for coding agents. Supports Docker and Kubernetes backends with SSH access, snapshots, health monitoring, metrics, interactive terminals, and file watching.
Author: Syntera AI
Latest version: 1.0.0

# @syntera-ai/sandbox

> **Provider-based sandbox SDK for coding agents.** Drop-in replacement for Daytona with Docker and Kubernetes backends. Deploy on AWS, GCP, or your own datacenter.

[![npm version](https://img.shields.io/npm/v/@syntera-ai/sandbox.svg)](https://www.npmjs.com/package/@syntera-ai/sandbox)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Node.js Version](https://img.shields.io/node/v/@syntera-ai/sandbox.svg)](https://nodejs.org)

## Features

- 🐳 **Docker Provider** — Single-node, development, CI/CD
- ☸️ **Kubernetes Provider** — Production, multi-tenant, auto-scaling
- 🔑 **SSH Access** — Full SSH into sandboxes with auto-key management, tunneling, interactive shell
- 📸 **Snapshots** — Save and restore workspace state for checkpointing and rollback
- 💊 **Health Monitoring** — Exec/TCP/HTTP health checks with continuous monitoring
- 📊 **Resource Metrics** — CPU, memory, disk, network usage collection
- 💻 **Interactive Terminals** — PTY sessions with resize, multiple concurrent shells
- 👁️ **File Watching** — Real-time filesystem change events via inotify
- 🏊 **Sandbox Pool** — Pre-warmed sandboxes for sub-second creation
- 📁 **File System** — Read, write, list, stat, copy, move files inside sandboxes
- 🔧 **Command Execution** — exec with timeout, streaming, env vars, working directory
- 🌐 **Port Management** — Discover listening ports, generate preview URLs
- 🔒 **Security** — Drop capabilities, seccomp, resource limits, non-root user
- 🏷️ **Labels & Discovery** — Tag sandboxes, find by labels
- 📡 **Events** — Subscribe to lifecycle events (created, stopped, health changes, etc.)
- 🚀 **Deploy Anywhere** — Terraform for AWS EKS, GCP GKE, Docker Compose, bare K8s

## Quick Start

```bash
npm install @syntera-ai/sandbox
```

### Docker (Development)

```typescript
import { createSandbox } from '@syntera-ai/sandbox';

const client = await createSandbox({
  provider: 'docker',
  defaults: {
    image: 'syntera/sandbox-base:latest',
    cpu: 2,
    memory: 4096,
  },
});

// Create a sandbox
const sandbox = await client.create({
  ports: [3000],
  env: { NODE_ENV: 'development' },
});

// Execute commands
const result = await sandbox.exec('echo "Hello!"');
console.log(result.stdout); // "Hello!"

// File operations
await sandbox.fs.write('/home/sandbox/app.js', 'console.log("hi")');
const content = await sandbox.fs.read('/home/sandbox/app.js');

// Cleanup
await sandbox.destroy();
await client.shutdown();
```

### Kubernetes (Production)

```typescript
const client = await createSandbox({
  provider: 'kubernetes',
  kubernetes: {
    namespace: 'syntera-sandboxes',
    serviceAccount: 'syntera-sandbox-manager',
    nodeSelector: { dedicated: 'syntera-sandbox' },
  },
  defaults: {
    image: 'your-registry/syntera/sandbox-swe-agent:latest',
    cpu: 2,
    memory: 4096,
  },
  pool: {
    enabled: true,
    min: 5,
    max: 30,
    idleTimeout: 300,
  },
});
```

## API Reference

### `createSandbox(config): Promise<SynteraSandbox>`

Creates and initializes a sandbox client.

```typescript
interface SandboxConfig {
  provider: 'docker' | 'kubernetes';
  docker?: DockerProviderConfig;
  kubernetes?: KubernetesProviderConfig;
  defaults?: SandboxDefaults;
  pool?: PoolConfig;
  logger?: LoggerConfig;
}
```

### `SynteraSandbox`

| Method | Description |
|--------|-------------|
| `create(params?)` | Create a new sandbox (or acquire from pool) |
| `get(id)` | Get sandbox by ID |
| `list(filter?)` | List sandboxes (optionally filtered) |
| `findOne(filter)` | Find first sandbox matching filter |
| `stop(id)` | Stop sandbox (or release to pool) |
| `destroy(id)` | Permanently destroy sandbox |
| `on(event, handler)` | Subscribe to events |
| `shutdown()` | Clean up all resources |

### `ISandboxInstance`

| Method | Description |
|--------|-------------|
| `exec(cmd, opts?)` | Execute a command, return `{ exitCode, stdout, stderr }` |
| `execStream(cmd, opts?)` | Streaming execution with stdin/stdout callbacks |
| `start()` | Start a stopped sandbox |
| `stop()` | Stop the sandbox |
| `destroy()` | Permanently destroy |
| `getState()` | Get current state |
| `waitUntilRunning(timeout?)` | Block until sandbox is running |
| `setLabels(labels)` | Set metadata labels |
| `getLabels()` | Get metadata labels |
| `fs.read(path)` | Read file content |
| `fs.write(path, content)` | Write file |
| `fs.exists(path)` | Check if path exists |
| `fs.list(path)` | List directory contents |
| `fs.delete(path, recursive?)` | Delete file/directory |
| `fs.mkdir(path, recursive?)` | Create directory |
| `fs.stat(path)` | Get file stats |
| `fs.copy(src, dest)` | Copy file/directory |
| `fs.move(src, dest)` | Move file/directory |
| `getPortUrl(port)` | Get URL for an exposed port |
| `listPorts()` | List all listening ports |

### Security Profiles

```typescript
import {
  DEFAULT_SECURITY_PROFILE,    // Balanced — drops dangerous caps
  STRICT_SECURITY_PROFILE,     // Maximum isolation
  PERMISSIVE_SECURITY_PROFILE, // Dev/testing only
} from '@syntera-ai/sandbox';

const sandbox = await client.create({
  securityProfile: STRICT_SECURITY_PROFILE,
});
```

### Resource Limits

```typescript
import {
  DEFAULT_RESOURCE_LIMITS,  // 2 CPU, 4GB RAM, 10GB disk
  SMALL_RESOURCE_LIMITS,    // 1 CPU, 2GB RAM, 5GB disk
  LARGE_RESOURCE_LIMITS,    // 4 CPU, 8GB RAM, 20GB disk
} from '@syntera-ai/sandbox';
```

## Deployment

### Option 1: Docker Compose (Dev / Single Node)

```bash
# Build images
cd images/base && docker build -t syntera/sandbox-base:latest .
cd ../swe-agent && docker build -t syntera/sandbox-swe-agent:latest .

# Start infrastructure
cd deploy/docker-compose && docker compose up -d
```

SDK config:
```typescript
{ provider: 'docker', docker: { socketPath: '/var/run/docker.sock', network: 'syntera-sandbox-net' } }
```

### Option 2: Kubernetes (On-Prem Datacenter)

```bash
# Apply manifests to your cluster
kubectl apply -f deploy/kubernetes/namespace.yaml
kubectl apply -f deploy/kubernetes/rbac.yaml
kubectl apply -f deploy/kubernetes/configmap.yaml
kubectl apply -f deploy/kubernetes/resource-limits.yaml
```

SDK config:
```typescript
{ provider: 'kubernetes', kubernetes: { namespace: 'syntera-sandboxes' } }
```

### Option 3: AWS (EKS)

```bash
cd deploy/aws/terraform
terraform init && terraform apply -var="environment=prod"
# Follow output instructions
```

See [`deploy/aws/README.md`](deploy/aws/README.md) for details.

### Option 4: GCP (GKE)

```bash
cd deploy/gcp/terraform
terraform init && terraform apply -var="gcp_project=YOUR_PROJECT"
# Follow output instructions
```

See [`deploy/gcp/README.md`](deploy/gcp/README.md) for details.

## On-Premises / Datacenter Deployment Guide

For running on your own cluster:

### Prerequisites
- Kubernetes 1.25+ cluster (K3s, RKE2, kubeadm, etc.)
- Container registry (Harbor, Docker Registry, etc.)
- `kubectl` access with cluster-admin

### Steps

```bash
# 1. Set up a local registry (if you don't have one)
docker run -d -p 5000:5000 --restart=always --name registry registry:2

# 2. Build and push images to your registry
docker build -t your-registry:5000/syntera/sandbox-base:latest images/base/
docker push your-registry:5000/syntera/sandbox-base:latest

docker build -t your-registry:5000/syntera/sandbox-swe-agent:latest images/swe-agent/
docker push your-registry:5000/syntera/sandbox-swe-agent:latest

# 3. Apply K8s manifests
kubectl apply -f deploy/kubernetes/

# 4. (Optional) Dedicate nodes for sandboxes
kubectl label nodes <node-name> dedicated=syntera-sandbox
kubectl taint nodes <node-name> dedicated=syntera-sandbox:NoSchedule
```

### SDK config for on-prem:
```typescript
const client = await createSandbox({
  provider: 'kubernetes',
  kubernetes: {
    namespace: 'syntera-sandboxes',
    serviceAccount: 'syntera-sandbox-manager',
    nodeSelector: { dedicated: 'syntera-sandbox' },
    tolerations: [{
      key: 'dedicated',
      operator: 'Equal',
      value: 'syntera-sandbox',
      effect: 'NoSchedule',
    }],
    imagePullSecrets: ['registry-creds'], // If using private registry
  },
  defaults: {
    image: 'your-registry:5000/syntera/sandbox-swe-agent:latest',
    cpu: 2,
    memory: 4096,
  },
  pool: {
    enabled: true,
    min: 3,
    max: 20,
    idleTimeout: 300,
  },
});
```

### Hardware Recommendations

| Scale | Sandbox Nodes | CPU | RAM | Disk | Concurrent Sandboxes |
|-------|--------------|-----|-----|------|---------------------|
| Small | 2 | 8 cores | 32 GB | 200 GB SSD | ~8 |
| Medium | 5 | 16 cores | 64 GB | 500 GB SSD | ~30 |
| Large | 10+ | 32 cores | 128 GB | 1 TB NVMe | ~100+ |

## Migration from Daytona

See [`examples/migration-from-daytona.ts`](examples/migration-from-daytona.ts) for a complete migration guide.

### Quick Mapping

| Daytona API | @syntera-ai/sandbox Equivalent |
|-------------|---------------------------|
| `new Daytona({ apiKey })` | `createSandbox({ provider: 'docker' })` |
| `client.create(params)` | `client.create(params)` |
| `client.get(id)` | `client.get(id)` |
| `client.stop(sandbox)` | `client.stop(id)` |
| `client.delete(sandbox)` | `client.destroy(id)` |
| `client.findOne({ labels })` | `client.findOne({ labels })` |
| `sandbox.process.executeCommand(cmd, dir)` | `sandbox.exec(cmd, { workdir: dir })` |
| `sandbox.state === SandboxState.STARTED` | `sandbox.state === SandboxState.RUNNING` |
| `sandbox.start()` | `sandbox.start()` |
| `sandbox.setLabels(labels)` | `sandbox.setLabels(labels)` |
| `sandbox.waitUntilStarted(timeout)` | `sandbox.waitUntilRunning(timeout)` |

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                     @syntera-ai/sandbox SDK                     │
│                                                              │
│  ┌──────────────────────────────────────────────────────┐   │
│  │              SynteraSandbox (Client)                   │   │
│  │  create() | get() | list() | stop() | destroy()      │   │
│  └────────────────────────┬─────────────────────────────┘   │
│                           │                                  │
│  ┌────────────────────────┼─────────────────────────────┐   │
│  │              SandboxPool (optional)                    │   │
│  │  acquire() | release() | maintain()                   │   │
│  └────────────────────────┬─────────────────────────────┘   │
│                           │                                  │
│  ┌────────────┬───────────┴──────────┬──────────────────┐   │
│  │ ISandbox   │    ISandboxProvider   │                  │   │
│  │ Instance   │                       │                  │   │
│  │            │  ┌─────────────────┐  │                  │   │
│  │  exec()    │  │ DockerProvider  │  │  SandboxFileSystem│  │
│  │  fs.*      │  │ K8sProvider     │  │  PortManager      │  │
│  │  ports     │  │ (your custom)   │  │  Security         │  │
│  └────────────┘  └─────────────────┘  └──────────────────┘  │
└─────────────────────────────────────────────────────────────┘
```

## License

MIT