Processes & Shells
Execute commands, manage long-running processes, replay their output, and open interactive shells.
Every guest process is an entry in the VM’s kernel process table, never a host process.
| Hosted | Library | |
|---|---|---|
| Run to completion with an argument array | v1.process.run({ command, args }) | process.execFile(file, args) |
| Run a shell command line | v1.process.run({ command: "sh", args: ["-c", line] }) | process.exec(line) |
| Start a long-running process | v1.process.spawn({ command, args }) returns { generation, pid } | process.spawn(command, args) returns { pid } |
import { createAgentOsClient } from "@rivet-dev/agentos";
const client = createAgentOsClient({ endpoint: "https://api.rivet.dev" });
const vm = client.agentOS.getOrCreate(["my-vm"]);
// One-shot execution
const result = await vm.v1.process.run({
command: "ls",
args: ["-la", "/home/agentos"],
options: { captureStdio: true },
});
console.log(result.stdout);
// Long-running process with live output and exit events.
const conn = vm.connect();
await conn.ready;
const server = await conn.v1.process.spawn({
command: "node",
args: ["/tmp/server.mjs"],
});
conn.on("process.output", (event) => {
if (event.process.pid !== server.pid) return;
console.log(event.stream, new TextDecoder().decode(event.data));
});
conn.on("process.exit", (event) => {
if (event.process.pid !== server.pid) return;
console.log("exited:", event.status.exitCode);
});
// Write to stdin
await conn.v1.process.stdin.write({ process: server, data: "some input\n" });
// Stop or kill
await conn.v1.process.signal({ process: server, signal: "SIGTERM" });
// One-shot execution
const result = await vm.process.exec("ls -la /home/agentos");
console.log(result.stdout);
// Long-running process with portable output and exit subscriptions.
await vm.filesystem.writeFile(
"/tmp/server.mjs",
'import http from "http"; http.createServer((req, res) => res.end("ok")).listen(3000); console.log("listening");',
);
const { pid } = await vm.process.spawn("node", ["/tmp/server.mjs"]);
vm.onProcessOutput(pid, (event) =>
console.log(event.stream, new TextDecoder().decode(event.data)),
);
vm.onProcessExit(pid, (event) => console.log("exited:", event.exitCode));
// Write to stdin
await vm.process.writeStdin(pid, "some input\n");
// Stop or kill
await vm.process.signal(pid, "SIGTERM");
Process arguments are passed as individual argv entries. An empty string is a valid argument; it is not dropped or treated as an omitted argument. Empty commands or working directories are invalid input.
Manage running processes
| Operation | Hosted | Library |
|---|---|---|
| Write and close stdin | v1.process.stdin.write, v1.process.stdin.close | process.writeStdin, process.closeStdin |
| Send a signal | v1.process.signal | process.signal, process.kill |
| Resize a PTY | v1.process.pty.resize | process.resizePty |
| Wait for exit | v1.process.wait | process.wait |
| Inspect | v1.process.get, v1.process.list, v1.process.tree | process.get, process.list, process.tree |
Hosted operations take the process handle { generation, pid }; library
operations take the pid. A hosted handle from before a v1.vm.restart fails
with stale_generation.
get and list report startedAtMs as a Unix timestamp in milliseconds.
tree includes guest child processes as well as processes launched through the
API, so it can show more than you started. Use the returned handle or pid
rather than reconstructing one from a node; guest children that were not
launched through the API have no hosted process handle.
A process wait returns an exit only after agentOS observes a guest exit. A rejected launch or lost exit observation rejects the wait instead of inventing an exit code. An observation failure does not prove the guest has stopped; inspect the VM or recreate it before assuming it is safe to retry work.
Output events and replay
Process output can be replayed after the fact, even after the process has
exited or a live event was missed. Hosted VMs retain output for every spawned
process; in the library, pass output: { retainEvents: true } to spawn.
Then page through retained output with a sequence cursor.
import { createAgentOsClient } from "@rivet-dev/agentos";
const client = createAgentOsClient({ endpoint: "https://api.rivet.dev" });
const vm = client.agentOS.getOrCreate(["my-vm"]);
const shell = await vm.v1.process.spawn({ command: "sh", args: [] });
await vm.v1.process.stdin.write({ process: shell, data: "echo from the background\n" });
await vm.v1.process.stdin.close({ process: shell });
await vm.v1.process.wait({ process: shell });
// Later, from any client
const replay = await vm.v1.process.output.read({
process: shell,
maxEvents: 32,
maxBytes: 64 * 1024,
});
console.log(replay.events.length, replay.nextCursor);
import { AgentOs } from "@rivet-dev/agentos-core";
const runtime = await AgentOs.create();
try {
const shell = await runtime.process.spawn("sh", [], {
output: { retainEvents: true }, // buffer output so it can be replayed
});
await runtime.process.writeStdin(shell.pid, "echo from the background\n");
await runtime.process.resizePty(shell.pid, { cols: 120, rows: 40 });
await runtime.process.closeStdin(shell.pid);
const exit = await runtime.process.wait(shell.pid);
const replay = await runtime.process.readOutput(shell.pid);
console.log(exit.exitCode, replay.events.length); // 0 1
} finally {
await runtime.dispose();
}
Pass the last cursor as after to read the next page. A replay page reports
nextCursor, hasMore, and truncated. Live events are low-latency hints:
process.output and process.exit on a hosted connection, or
vm.onProcessOutput and vm.onProcessExit in the library. Retention is
bounded; see Resource Limits for the defaults.
Interactive shells
Interactive terminals allocate a kernel PTY and start a shell attached to it.
| Operation | Hosted | Library |
|---|---|---|
| Open | v1.terminal.open | terminal.open, returns a shellId |
| Write input | v1.terminal.stdin.write | terminal.write |
| Resize | v1.terminal.pty.resize | terminal.resize |
| Wait and close | v1.terminal.wait, v1.terminal.close | terminal.wait, terminal.close |
| Output | terminal.output and terminal.exit events, v1.terminal.output.read replay | vm.onShellData, vm.onShellStderr, vm.onShellExit |
Hosted VMs also list open terminals with v1.terminal.list.