runtime:system

Child processes. A command is a program plus an argv — there is no shell, so nothing is word-split, glob-expanded, or re-parsed. Output moves over web streams.

Capability: Run

Spawning is the one grant that ends the sandbox: a child runs outside every confinement here — no capability check, no root jail, no execution deadline. Never implied by another capability. Status: Available.

Import

JavaScript
import { Command } from "runtime:system";

// Or the default aggregate:
import system from "runtime:system";

Exports

ExportTypeDescription
CommandclassA command to run: new Command(program, options?).
ChildProcessclassA running child, from spawn(). Not constructed directly.

new Command(program, options?)

program is a path (absolute, or relative to cwd) or a bare name looked up on the host PATH. The env you pass describes the child's environment, never where the runtime looks for executables.

options is an object with only the keys below. An array (Node's spawn(cmd, args) shape) or any other key is a TypeError, so a misplaced argument list is never silently dropped.

OptionTypeDefaultDescription
args(string | number | boolean)[][]Passed verbatim — no quoting or escaping needed.
cwdstring | URLthe parent'sThe child's working directory.
envRecord<string, string | Secret | undefined>{}The child's environment. A Secret is unwrapped for the child; undefined removes an inherited key.
inheritEnvbooleanfalseStart from the host environment. Needs Env as well as Run.
stdin"null" | "piped" | "inherit", or a body"null"A body — string, bytes, Blob, Response, ReadableStream — is written to the child, then stdin closed.
stdout / stderr"piped" | "inherit" | "null""piped"How the output is connected.
signalAbortSignal—Aborting kills the child; output() rejects with the reason.
timeoutnumber (ms)—Kill the child after this long; output() rejects with a TimeoutError.
killSignalSignalName"SIGTERM"Signal used by kill(), a timeout, or an abort.
maxBuffernumber (bytes)16777216output() only: past this the child is killed and the call throws ERR_MAX_BUFFER.
MethodTypeDescription
output()Promise<CommandOutput>Run to completion, collecting output. Both streams are read while the child runs, so a full pipe cannot deadlock the wait.
spawn()Promise<ChildProcess>Start the child. Async: a failure to start belongs to this call, not to a stream settled later.

CommandOutput is { success, code, signal, stdout, stderr } — code is null when a signal ended the process, stdout/stderr are Uint8Array.

ChildProcess

MemberTypeDescription
pidnumberThe OS process id.
stdinWritableStream | nullnull unless piped. Closing it is the child's EOF.
stdout / stderrReadableStream<Uint8Array> | nullnull unless piped. Pulled chunk by chunk.
statusPromise<{ success, code, signal }>Resolves when the child exits.
kill(signal?)(SignalName?) => Promise<void>Defaults to killSignal. A no-op on an exited child.
[Symbol.asyncDispose]()await using kills and reaps at end of scope.
What keeps the program alive

Streams are created on first use, and reading status is what holds the program open. A child nobody waits on keeps nothing alive — and is killed, not orphaned, when the runtime exits.

Examples

JavaScript
import { Command } from "runtime:system";

// Buffered
const { success, code, stdout } = await new Command("git", {
  args: ["rev-parse", "HEAD"],
}).output();

// Streaming, both ways
const child = await new Command("ffmpeg", {
  args: ["-i", "pipe:0", "-f", "mp3", "pipe:1"],
  stdin: request.body,
  stderr: "inherit",
}).spawn();
return new Response(child.stdout);

// Bounded
await new Command("slow-tool", { timeout: 30_000, killSignal: "SIGKILL" }).output();

Not provided

AbsentWhy
A shell (exec, shell: true, $`…`)The shell-injection class stays out.
fork() / IPCWorker processes want their own design.
stdio arrays, raw fdsAn fd hands the guest authority over anything inherited.
detached, uid/gidPrivilege manipulation belongs to the embedder.
Sync variantsOps run inside the async runtime.
PTYThis runtime pipes.
Last updated on
Edit this page