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

@ai-craft/sandbox

v1.0.0

Published

AI-agent sandboxing SDK — sandcastle-shaped, multi-provider

Readme

@ai-craft/sandbox

AI-agent sandboxing SDK — provider abstraction, multi-provider lifecycle management.

Install

npm install @ai-craft/sandbox

Quick Start

import { createSandbox } from '@ai-craft/sandbox';
import { FakeSandboxProvider } from '@ai-craft/sandbox/providers/fake';

const provider = new FakeSandboxProvider();

// Create a sandbox (automatically selects image based on provider)
const sb = await createSandbox({ provider, image: 'ubuntu:22.04' });

try {
  const result = await sb.exec(['echo', 'hello world']);
  console.log(result.stdout); // "hello world\n"
} finally {
  await sb.stop();
}

// Or use the AsyncDisposable pattern:
{
  await using sb = await createSandbox({ provider });
  await sb.exec(['apt-get', 'install', '-y', 'git']);
}

Default agent — ai-agent

By default, @ai-craft/sandbox runs ai-agent (the multi-provider AI agent CLI from @ai-craft/agent-cli) inside any sandbox built from the standard image.

Why

Native to the SDK — bundled into the default sandbox image at /usr/local/bin/ai-agent so pods can drive a multi-provider plan-execute harness with prompt caching and cost-optimized model routing out-of-the-box. No host round-trips per tool call: the loop runs in-pod against local FS/shell. Other coding CLIs (claude, codex, aider, opencode) coexist as opt-in overrides.

How (default run())

import { run } from '@ai-craft/sandbox';
import { DockerProvider } from '@ai-craft/sandbox/providers/docker';

// No `agent` argument — defaults to nativeAgent() (the `ai-agent` CLI inside the pod).
await run({
  sandbox: { provider: new DockerProvider(), image: 'ai-craft-sandbox:latest' },
});

Override

Pass any of the four alternate factories — claudeCode, codex, aider, opencode — to swap the in-pod agent:

import { run } from '@ai-craft/sandbox';
import { claudeCode } from '@ai-craft/sandbox/agents/claude-code';
// also available: codex, aider, opencode (each from their own subpath)

await run({
  agent: claudeCode(),
  sandbox: { provider: new DockerProvider(), image: 'ai-craft-sandbox:latest' },
});

Build the image

pnpm exec nx run sandbox:image

This depends on agent-cli:build automatically — the resulting dist/packages/agent-cli/main.js is baked into /usr/local/bin/ai-agent during docker build. The image is tagged ai-craft-sandbox:latest for local use.

Permission model

Inside the pod, ai-agent's bash tool runs commands permission-less by design. As defense-in-depth a small deny-list blocks destructive patterns (force-push, git reset --hard, rm -rf /, DROP TABLE, sudo, pipe-to-shell, etc.). When a command matches, the tool returns a structured error string identifying the matched pattern.

Set AGENT_DANGEROUS_OK=1 (per-pod env var) to bypass the deny-list when you know what you are doing. The deny-list is defense-in-depth, not a security guarantee — adversarial bypass via shell quoting is possible.

See packages/agent-cli/README.md#permission-model for the full deny-list and override path.

Policy Model

@ai-craft/sandbox supports a declarative SandboxPolicy that callers can attach to any createSandbox() call. Policy is always optional — absent policy leaves all existing behavior unchanged at every call site.

Three rule types

| Surface | Semantics | Notes | |---------|-----------|-------| | Writes (filesystem.write) | Allow-only | Empty allowWrite means deny all writes. | | Reads (filesystem.read) | Deny-then-allow | denyRead closes first; allowRead carves back within denied regions. | | Network (network) | Allow-only | allowedDomains is enforced. deniedDomains takes precedence over allowedDomains. |

Example

import { createSandbox, type SandboxPolicy } from '@ai-craft/sandbox';
import { DockerProvider } from '@ai-craft/sandbox/providers/docker';

const policy: SandboxPolicy = {
  filesystem: {
    write: { allowWrite: ['/tmp/workspace'] },
    read: { denyRead: ['~/.ssh', '~/.aws/credentials'], allowRead: ['/etc/hosts'] },
  },
  network: { allowedDomains: ['api.anthropic.com'] },
};

const sb = await createSandbox({
  provider: new DockerProvider(),
  image: 'ubuntu:22.04',
  policy,
  failIfUnavailable: false, // warn-only mode; set true to fail on unenforced rules
});

Provider Capability Matrix

Enforcement levels per provider for each policy surface:

| Provider | reads | writes | network | exec | |----------|-------|--------|---------|------| | DockerProvider | translated | translated | unenforced* | unenforced | | PodmanProvider | translated | translated | unenforced* | unenforced | | KubernetesProvider | translated | translated | unenforced* | unenforced | | NoSandboxProvider | unenforced | unenforced | unenforced | unenforced | | FakeSandboxProvider | unenforced | unenforced | unenforced | unenforced |

Enforcement levels:

  • native — enforced by the OS or runtime directly (no translation needed)
  • translated — policy is translated into provider-native constraints (volume mounts, etc.)
  • unenforced — provider cannot enforce this surface; a SandboxViolationEvent with severity: 'unenforced' is emitted

*Network domain filtering for Docker/Podman/Kubernetes currently sets --network none + HTTP_PROXY env as a placeholder. Full per-domain enforcement requires the Stage 4 proxy bridge. With failIfUnavailable: true, these providers will throw SandboxUnenforcedPolicyError when network.allowedDomains is set.

Providers

| Provider | Description | Subpath | |---|---|---| | FakeSandboxProvider | In-memory stub for testing | @ai-craft/sandbox/providers/fake | | KubernetesProvider | Real K8s pod execution | @ai-craft/sandbox/providers/kubernetes | | DockerProvider | Local Docker containers | @ai-craft/sandbox/providers/docker | | PodmanProvider | Local Podman containers | @ai-craft/sandbox/providers/podman | | E2BProvider | E2B cloud sandboxes | @ai-craft/sandbox/providers/e2b | | DaytonaProvider | Daytona cloud sandboxes | @ai-craft/sandbox/providers/daytona | | NoSandboxProvider | Run directly on host (no isolation) | @ai-craft/sandbox/providers/no-sandbox |

Subpath Exports

| Import path | Exports | |---|---| | @ai-craft/sandbox | createSandbox, createWorktree, run, types | | @ai-craft/sandbox/providers/fake | FakeSandboxProvider, FakeProviderHandle | | @ai-craft/sandbox/providers/kubernetes | KubernetesProvider | | @ai-craft/sandbox/providers/docker | DockerProvider | | @ai-craft/sandbox/testing | runProviderContract | | @ai-craft/sandbox/agents/claude-code | ClaudeCodeAgent | | @ai-craft/sandbox/agents/codex | CodexAgent |

Key Types

| Type | Description | |---|---| | Sandbox | AsyncDisposable sandbox handle returned by createSandbox() | | SandboxProvider | Provider interface (implement to add a new backend) | | ExecResult | { exitCode, stdout, stderr, durationMs, timedOut, truncated } | | ExecOptions | { cwd, env, stdin, signal, timeoutMs, idleTimeoutMs, onLine } | | CreateSandboxOptions | { provider, image?, env?, mounts?, network?, resources?, hooks? } |

Local machine push (SSH)

When an agent session ends, you can have the worktree push its branch directly to your local machine over SSH — no GitHub round-trip required. This is useful when the orchestrator runs on a remote host (cloud VM, dev container, K8s pod) and you want commits available locally without pushing to a hosted origin.

One-time setup (on your laptop)

# Create a bare repo to receive the push (once per project)
git init --bare ~/sandbox-repos/myproject.git

# Make your laptop reachable from wherever the orchestrator runs
# (Tailscale, LAN IP, or a public SSH endpoint)

Orchestrator configuration

Set two environment variables before starting the orchestrator:

export [email protected]
export SANDBOX_LOCAL_REPO_PATH=/Users/me/sandbox-repos/myproject.git

When both variables are set, tools/sandbox-run.mjs automatically wires the worktree to push to your laptop over SSH instead of origin. Full git history is preserved.

Auto-bootstrap: if the bare repo does not yet exist on the laptop, the SDK will SSH in, run git init --bare, and retry the push automatically.

SSH auth: the push runs on the orchestrator host using ~/.ssh/ keys. No extra mount or key generation is needed if your SSH agent is already configured.

Retrieving commits on your laptop

cd ~/myproject
git fetch ~/sandbox-repos/myproject.git <branch-name>
git checkout <branch-name>

Programmatic API

You can also pass pushDestination directly to createWorktree():

import { createWorktree } from '@ai-craft/sandbox';

const worktree = await createWorktree({
  repoPath: '/path/to/repo',
  strategy: {
    type: 'branch',
    name: 'sandbox/my-session',
    push: true,
    pushDestination: {
      sshHost: '[email protected]',
      repoPath: '/Users/me/sandbox-repos/myproject.git',
      // remoteName: 'sandbox-local',  // optional; defaults to 'sandbox-local'
    },
  },
});

const result = await worktree.finalize();
console.log(result.pushed); // true

Prerequisite: the orchestrator host must be able to reach the laptop over SSH (Tailscale, VPN, or LAN). This is a deployment concern — the SDK manages the git protocol, not the network path.

Requirements

  • Node ≥ 22.0.0

Build

nx build sandbox

Test

nx test sandbox