Processes & Shell
Execute commands, spawn long-running processes, and open interactive shells in agentOS VMs.
Run commands with one-shot exec, spawn long-running processes with streaming stdout/stderr and stdin, manage their lifecycle (stop, kill, wait, inspect), open interactive PTY-backed shells, and inspect the process tree across all VM runtimes.
One-shot execution
Use exec to run a command and wait for completion. Returns stdout, stderr, and exit code.
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";
const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });
const result = await client.vm.getOrCreate("my-agent").exec("echo hello && ls /home/agentos");
console.log("stdout:", result.stdout);
console.log("stderr:", result.stderr);
console.log("exit code:", result.exitCode);
Spawn a long-running process
Use spawn for processes that run in the background. Output is streamed via processOutput and processExit events.
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";
const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });
const agent = client.vm.getOrCreate("my-agent");
const conn = agent.connect();
// Subscribe to process output
conn.on("processOutput", (data) => {
const text = new TextDecoder().decode(data.data);
console.log(`[pid ${data.pid}] ${data.stream}: ${text}`);
});
conn.on("processExit", (data) => {
console.log(`[pid ${data.pid}] exited with code ${data.exitCode}`);
});
// Spawn a dev server
const { pid } = await agent.spawn("node", ["/home/agentos/server.js"]);
console.log("Started process:", pid);
Write to stdin
Send input to a running process.
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";
const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });
const agent = client.vm.getOrCreate("my-agent");
const { pid } = await agent.spawn("cat", []);
// Write to stdin
await agent.writeProcessStdin(pid, "hello from stdin\n");
// Close stdin when done
await agent.closeProcessStdin(pid);
// Wait for the process to exit
const exitCode = await agent.waitProcess(pid);
console.log("exit code:", exitCode);
Process lifecycle
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";
const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });
const agent = client.vm.getOrCreate("my-agent");
const { pid } = await agent.spawn("node", ["/home/agentos/server.js"]);
const processStatus = (process: { running: boolean; exitCode?: number | null }) =>
process.running ? "running" : `exited ${process.exitCode ?? ""}`.trim();
// List all processes tracked by the VM
const processes = await agent.listProcesses();
for (const p of processes) {
console.log(p.pid, p.command, p.args.join(" "), processStatus(p));
}
// Inspect a specific process by pid
const info = await agent.getProcess(pid);
console.log(processStatus(info), info.exitCode);
// Graceful stop (SIGTERM)
await agent.stopProcess(pid);
// Force kill (SIGKILL)
await agent.killProcess(pid);
Interactive shells
Open an interactive shell with PTY support. Shell data is streamed via shellData events.
import { createClient } from "@rivet-dev/agentos/client";
import type { registry } from "./server";
const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });
const agent = client.vm.getOrCreate("my-agent");
const conn = agent.connect();
// Stream the interactive process's output as it is produced
conn.on("processOutput", (data) => {
const text = new TextDecoder().decode(data.data);
process.stdout.write(text);
});
// Spawn an interactive shell process
const { pid } = await agent.spawn("sh", []);
// Drive it by writing commands to stdin
await agent.writeProcessStdin(pid, "ls -la /home/agentos\n");
// Close stdin to let the shell exit, then wait for it
await agent.closeProcessStdin(pid);
await agent.waitProcess(pid);
Attach a shell to a Node terminal
The Node-specific @rivet-dev/agentos/node entrypoint attaches an actor’s PTY
shell to the current process terminal. It forwards stdin and output, enables raw
mode, propagates terminal resizes, restores terminal state, and returns the guest
exit code.
import { createClient } from "@rivet-dev/agentos/client";
import { attachShell } from "@rivet-dev/agentos/node";
import type { registry } from "./server";
const client = createClient<typeof registry>({
endpoint: "http://localhost:6420",
});
const agent = client.vm.getOrCreate("node-shell");
const connection = agent.connect();
try {
process.exitCode = await attachShell(connection, {
command: "bash",
args: ["--input-backend", "minimal", "-i"],
cwd: "/home/agentos",
});
} finally {
await connection.dispose();
}