The Problem

Developers need a single, sandbox‑safe way to drive multiple coding‑agent back‑ends (Claude Code, Codex, OpenCode, Cursor, Amp, Pi). Existing SDKs are agent‑specific, assume local execution, and expose divergent APIs, forcing repetitive integration work and risking security when agents run on production hosts.

What This Does

Sandbox Agent provides a lightweight Rust daemon (sandbox-agent server) that runs inside any sandbox (Docker, E2B, Daytona, Vercel) and exposes a universal HTTP + SSE API. A TypeScript SDK (sdks/typescript/src/client.ts) talks to that API, offering a single client surface for all supported agents. The repo ships a full UI inspector, a CLI wrapper, and several runnable examples (e.g., examples/e2b/src/index.ts, examples/boxlite/src/index.ts) that demonstrate embedded‑mode and server‑mode usage.

Key files:

  • Server daemon – factory/packages/backend/src/index.ts (entry point main) builds the HTTP router and wires the actor system.
  • Actor core – factory/packages/backend/src/actors/context.ts (hub module, 14 dependents) holds request‑scoped state used by most backend actions.
  • Handoff logic – factory/packages/backend/src/actors/handoff/index.ts (25 functions, 13 types) creates, persists, and streams session handoffs.
  • TypeScript client – sdks/typescript/src/client.ts (196 functions, 32 callers) implements the universal API, performs network I/O, and marshals the universal session schema.

How It Is Wired

Execution starts in factory/packages/backend/src/index.ts:121 (main). main constructs the server, registers routes, and calls into the backend actor layer. The most traversed call chain is:

main → getActorRuntimeContext (32 callers) → getClient (26 callers) → fetch (30 callers) → requestJson (23 callers) → updateVersion (filesystem read)
  • getActorRuntimeContext lives in factory/packages/backend/src/actors/context.ts and is the primary hub; any change there ripples to 14 modules.
  • Session creation flows through factory/packages/backend/src/actors/handoff/index.ts (buildInitialHandoffs → minutesAgo → transcriptFromLegacyMessages).
  • The SDK calls sdks/typescript/src/client.ts:getClient, which performs an outbound HTTP request (fetch) and returns typed responses; this function is invoked by 26 internal callers, including the examples and the UI inspector.

The call graph shows 12 circular import groups, the most visible being between factory/packages/client/src/backend-client.ts, scripts/release/main.ts, and factory/packages/client/src/workbench-client.ts. These cycles increase cognitive load and risk breakage when refactoring.

Database writes occur in factory/packages/backend/src/actors/handoff/index.ts (e.g., upsertHandoffLookupRow) and factory/packages/backend/src/actors/workspace/actions.ts (workspaceWorkflowQueueName). External commands are spawned in factory/packages/backend/src/actors/sandbox-instance/index.ts (e.g., launching the Rust sandbox binary). Cryptographic material (crypto.randomBytes) is used in factory/packages/backend/src/actors/handoff-status-sync/index.ts:start.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/sandbox-agent
cd sandbox-agent

# Build the Rust daemon (requires Rust toolchain)
cargo build --release               # produces target/release/sandbox-agent

# Run the server inside a sandbox (example Docker)
docker build -f docker/runtime/Dockerfile -t sandbox-agent .
docker run -p 8080:8080 sandbox-agent

TypeScript SDK (example client):

pnpm install                      # installs sdks/typescript deps
node -e "import { SandboxAgentClient } from './sdks/typescript/src/client';
const c = new SandboxAgentClient({ baseUrl: 'http://localhost:8080' });
c.createSession({ agent: 'claude-code' }).then(console.log);"

Example embedded mode – see examples/e2b/src/index.ts which imports sdks/typescript/src/client.ts and calls run() to start a sandbox, then drives an agent via the universal API.

Configuration is driven by environment variables read in factory/packages/backend/src/integrations/git/index.ts (e.g., GITHUB_TOKEN) and by the OpenAPI spec under docs/api-reference.mdx. No additional config files are required to start the server.

Real‑World Use

A SaaS platform can spin up an isolated Docker sandbox per user, launch sandbox-agent server inside it, and use the TypeScript client from its backend to orchestrate code‑generation sessions. All events are streamed via SSE, stored in Postgres (via factory/packages/backend/src/actors/handoff/index.ts), and later replayed in the built‑in inspector UI (frontend/packages/inspector/src/App.tsx).

Code Health & Issues

  • Critical – .github/workflows/claude.yml exposes CLAUDE_CODE_OAUTH_TOKEN to fork‑triggered jobs.
  • High – GitHub Actions are pinned to tags only (dtolnay/rust-toolchain@stable, etc.).
  • Medium – No least‑privilege GITHUB_TOKEN permissions (ci.yaml).
  • Medium – Dependabot not configured; 43 manifests lack automated updates.
  • Medium – Base images in docker/runtime/Dockerfile use mutable tags (node:22-alpine).
  • Medium – No dependency‑vulnerability scan in CI.
  • Medium – Large binaries (sdks/gigacode/.../gigacode.exe) stored directly in repo.
  • Medium – Checkout step retains credentials (persist-credentials missing).
  • Low – Workflow jobs lack timeout-minutes.
  • Low – Repository lacks .editorconfig, .gitattributes, and formatter config.

Additional observations from the static analysis: 27 files are oversized (> 800 LOC), 28 files exhibit deep nesting (indentation > 8), and 12 modules participate in import cycles, all of which increase maintenance cost.

The Bottom Line

Sandbox Agent delivers a pragmatic, language‑agnostic bridge to multiple coding agents, with a clear separation between sandboxed Rust daemon and a typed TypeScript client. The codebase is functional but shows typical technical‑debt signals—large files, deep nesting, and import cycles—that will require refactoring for long‑term stability. It is suitable for teams that need immediate multi‑agent support and are prepared to address the highlighted security and maintainability concerns.