The sandbox API
Nimbus.fromEnv uses a colocated DO binding. Nimbus.connect uses the
authenticated remote API. Both return the same typed sandbox.
const box = nimbus.sandbox('job-123', { profile: 'default', // sandbox profile from your NimbusConfig tenant: 'acme', // namespaces the underlying DO: tenant:subject:id subject: 'agent',});
await box.ready(); // headless boot + profile preinstalls; memoizedawait box.destroy({ reason: 'job done' });Every call awaits ready(); call it directly to pay the boot cost first.
Running things
Section titled “Running things”Run one command, run source code, or start a process.
const result = await box.exec('npm test', { cwd: '/home/user/app', env: { CI: 'true' }, timeoutMs: 60_000, stdin: 'y\n',});// { command, exitCode, success, stdout, stderr, duration, timestamp }
await box.runCode('print(2 + 2)', { language: 'python', install: 'ifMissing' });
const proc = await box.startProcess('node --watch server.js');// NimbusExecResult & { pid, process, ports }Read and change files through the sandbox VFS.
await box.files.write('/home/user/app/server.js', code); // string | Uint8Arrayconst text = await box.files.read('/home/user/app/server.js');const bytes = await box.files.readBytes('/home/user/data.bin');const list = await box.files.list('/home/user'); // { name, type }[]await box.files.stat(path); await box.files.mkdir(path);await box.files.exists(path); await box.files.delete(path, { recursive: true });Runtimes
Section titled “Runtimes”Install allowed runtimes when a task needs them.
await box.runtimes.ensure(['python', 'clang']); // install if missingawait box.runtimes.list(); // { installed, available }Nimbus checks runtimes.allow before the install RPC.
Processes
Section titled “Processes”List processes and control their input, signals, size, and logs.
const procs = await box.processes.list(); // pid, command, state, exitCode…await box.processes.kill(pid);await box.processes.write(pid, 'input\n'); // stdinawait box.processes.signal(pid, 'SIGINT');await box.processes.resize(pid, { columns: 120, rows: 32 });const logs = await box.processes.logs(pid, { lines: 100 });attach returns an async iterable for live input and output.
const attachment = box.processes.attach(pid);await attachment.write('q');for await (const chunk of attachment) { // { seq, ts, stream: 'stdout' | 'stderr', data, binary? }}Expose an app through a path on the Nimbus deployment.
const port = await box.ports.expose(3000); // → { …, url: '/s/<id>/port/3000/' }await box.ports.list();await box.ports.unexpose(3000);The caller can use the URL directly with browser or session auth.
Agent tools
Section titled “Agent tools”Wrap the sandbox as a Proteus-style tool provider.
const provider = box.tools({ namespace: 'sandbox' });It includes files, exec, processes, ports, and runtimes.
Errors
Section titled “Errors”Remote calls throw NimbusRemoteError with status, optional code,
and the response body. The client validates wire payloads with zod, so a
drifted server fails instead of returning malformed shapes.