SandboxProcessManager
Added in: @mastra/core@1.7.0
Abstract base class for managing background processes in sandboxes. Provides methods to spawn processes, list them, get handles by PID, and kill them.
BlaxelSandbox, DaytonaSandbox, E2BSandbox, and LocalSandbox all include built-in process managers. You don't need to instantiate this class directly unless you're building a custom sandbox provider.
Usage exampleDirect link to Usage example
Access the process manager through the sandbox's processes property:
import { LocalSandbox } from '@mastra/core/workspace'
const sandbox = new LocalSandbox({ workingDirectory: './workspace' })
await sandbox.start()
// Spawn a background process
const handle = await sandbox.processes.spawn('node server.js', {
env: { PORT: '3000' },
onStdout: data => console.log(data),
})
// List all tracked processes
const procs = await sandbox.processes.list()
// Get a handle by PID
const proc = await sandbox.processes.get(handle.pid)
// Kill a process
await sandbox.processes.kill(handle.pid)
MethodsDirect link to Methods
spawn(command, options?)Direct link to spawncommand-options
Spawn a background process. Returns a ProcessHandle immediately without waiting for the process to finish.
const handle = await sandbox.processes.spawn('npm run dev', {
cwd: '/app',
env: { NODE_ENV: 'development' },
onStdout: data => console.log(data),
})
Parameters:
command:
options?:
timeout?:
env?:
cwd?:
onStdout?:
onStderr?:
abortSignal?:
Returns: Promise<ProcessHandle>
list()Direct link to list
List all tracked processes. Returns info about each process including PID, running state, and exit code.
const procs = await sandbox.processes.list()
for (const proc of procs) {
console.log(proc.pid, proc.running, proc.exitCode)
}
Returns: Promise<ProcessInfo[]>
get(pid)Direct link to getpid
Get a handle to a process by PID. Returns undefined if the process isn't found or has already been dismissed.
const handle = await sandbox.processes.get(1234)
if (handle) {
console.log(handle.stdout)
await handle.kill()
}
Returns: Promise<ProcessHandle | undefined>
kill(pid)Direct link to killpid
Kill a process by PID. Waits for the process to terminate before returning. Returns true if the process was killed, false if it wasn't found.
const killed = await sandbox.processes.kill(handle.pid)
Returns: Promise<boolean>
ProcessInfoDirect link to processinfo
Information about a tracked process, returned by list().
pid:
command?:
running:
exitCode?:
ProcessHandleDirect link to processhandle
Handle to a spawned background process. Provides methods to read output, send stdin, wait for completion, and kill the process.
You don't create ProcessHandle instances directly — they're returned by spawn() and get().
Usage exampleDirect link to Usage example
const handle = await sandbox.processes.spawn('npm run dev', {
onStdout: data => console.log(data),
})
// Read accumulated output
console.log(handle.pid)
console.log(handle.stdout)
console.log(handle.stderr)
console.log(handle.exitCode) // undefined while running
// Wait for completion
const result = await handle.wait()
// Send stdin
await handle.sendStdin('input data\n')
// Kill the process
await handle.kill()
PropertiesDirect link to Properties
pid:
stdout:
stderr:
exitCode:
command:
reader:
writer:
MethodsDirect link to Methods
wait(options?)Direct link to waitoptions
Wait for the process to exit and return the result. Optionally pass onStdout/onStderr callbacks to stream output while waiting. Callbacks are automatically removed when wait() resolves.
// Simple wait
const result = await handle.wait()
console.log(result.success, result.exitCode, result.stdout)
// Wait with streaming
const result = await handle.wait({
onStdout: data => process.stdout.write(data),
onStderr: data => process.stderr.write(data),
})
Parameters:
options?:
onStdout?:
onStderr?:
Returns: Promise<CommandResult>
The CommandResult object contains:
success:
exitCode:
stdout:
stderr:
executionTimeMs:
timedOut?:
killed?:
kill()Direct link to kill
Kill the process. Returns true if the process was killed, false if it had already exited.
const killed = await handle.kill()
Returns: Promise<boolean>
sendStdin(data)Direct link to sendstdindata
Send data to the process's stdin. Throws if the process has already exited or stdin isn't available.
await handle.sendStdin('console.log("hello")\n')
Returns: Promise<void>
Stream interopDirect link to Stream interop
ProcessHandle exposes reader and writer properties for integration with Node.js stream-based protocols like LSP or JSON-RPC:
import {
createMessageConnection,
StreamMessageReader,
StreamMessageWriter,
} from 'vscode-jsonrpc/node'
const handle = await sandbox.processes.spawn('typescript-language-server --stdio')
const connection = createMessageConnection(
new StreamMessageReader(handle.reader),
new StreamMessageWriter(handle.writer),
)
connection.listen()
Building a custom process managerDirect link to Building a custom process manager
To build a process manager for a custom sandbox provider, extend SandboxProcessManager and implement spawn() and list(). The base class automatically wraps your methods with ensureRunning() so the sandbox starts before any process operation.
import { SandboxProcessManager, ProcessHandle } from '@mastra/core/workspace'
import type { ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace'
class MyProcessManager extends SandboxProcessManager<MySandbox> {
async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {
// Your spawn implementation
const handle = new MyProcessHandle(/* ... */)
this._tracked.set(handle.pid, handle)
return handle
}
async list(): Promise<ProcessInfo[]> {
return Array.from(this._tracked.values()).map(handle => ({
pid: handle.pid,
running: handle.exitCode === undefined,
exitCode: handle.exitCode,
}))
}
}
Pass the process manager to your sandbox via the processes option in MastraSandbox:
class MySandbox extends MastraSandbox {
constructor() {
super({
name: 'MySandbox',
processes: new MyProcessManager(),
})
}
}
When a process manager is provided, MastraSandbox automatically creates a default executeCommand implementation that uses spawn() + wait(), so you don't need to implement both.