# Processes & Shell > Source: `src/content/docs/agent-os/processes.mdx` > Canonical URL: https://rivet.dev/docs/agent-os/processes > Description: Execute commands, spawn long-running processes, and open interactive shells in agentOS VMs. --- - **One-shot execution** with `exec` for simple commands - **Long-running processes** with `spawn`, stdout/stderr streaming, and stdin writing - **Process lifecycle** management with stop, kill, wait, and inspect - **Interactive shells** with PTY support for terminal I/O - **Process tree** visibility across all VM runtimes ## One-shot execution Use `exec` to run a command and wait for completion. Returns stdout, stderr, and exit code. ```ts @nocheck client.ts import { createClient } from "rivetkit/client"; import type { registry } from "./server"; const client = createClient("http://localhost:6420"); const agent = client.vm.getOrCreate(["my-agent"]); const result = await agent.exec("echo hello && ls /home/user"); console.log("stdout:", result.stdout); console.log("stderr:", result.stderr); console.log("exit code:", result.exitCode); ``` ```ts @nocheck server.ts import { agentOs } from "rivetkit/agent-os"; import { setup } from "rivetkit"; import common from "@rivet-dev/agent-os-common"; import pi from "@rivet-dev/agent-os-pi"; const vm = agentOs({ options: { software: [common, pi] }, }); export const registry = setup({ use: { vm } }); registry.start(); ``` ## Spawn a long-running process Use `spawn` for processes that run in the background. Output is streamed via `processOutput` and `processExit` events. ```ts @nocheck client.ts import { createClient } from "rivetkit/client"; import type { registry } from "./server"; const client = createClient("http://localhost:6420"); const agent = client.vm.getOrCreate(["my-agent"]); // Subscribe to process output agent.on("processOutput", (data) => { const text = new TextDecoder().decode(data.data); console.log(`[pid ${data.pid}] ${data.stream}: ${text}`); }); agent.on("processExit", (data) => { console.log(`[pid ${data.pid}] exited with code ${data.exitCode}`); }); // Spawn a dev server const { pid } = await agent.spawn("node", ["/home/user/server.js"]); console.log("Started process:", pid); ``` ```ts @nocheck server.ts import { agentOs } from "rivetkit/agent-os"; import { setup } from "rivetkit"; import common from "@rivet-dev/agent-os-common"; import pi from "@rivet-dev/agent-os-pi"; const vm = agentOs({ options: { software: [common, pi] }, }); export const registry = setup({ use: { vm } }); registry.start(); ``` ## Write to stdin Send input to a running process. ```ts @nocheck client.ts import { createClient } from "rivetkit/client"; import type { registry } from "./server"; const client = createClient("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); ``` ```ts @nocheck server.ts import { agentOs } from "rivetkit/agent-os"; import { setup } from "rivetkit"; import common from "@rivet-dev/agent-os-common"; import pi from "@rivet-dev/agent-os-pi"; const vm = agentOs({ options: { software: [common, pi] }, }); export const registry = setup({ use: { vm } }); registry.start(); ``` ## Process lifecycle ```ts @nocheck client.ts import { createClient } from "rivetkit/client"; import type { registry } from "./server"; const client = createClient("http://localhost:6420"); const agent = client.vm.getOrCreate(["my-agent"]); const { pid } = await agent.spawn("node", ["/home/user/server.js"]); // List all spawned processes const processes = await agent.listProcesses(); console.log(processes); // Get info about a specific process const info = await agent.getProcess(pid); console.log(info.running, info.exitCode); // Graceful stop (SIGTERM) await agent.stopProcess(pid); // Force kill (SIGKILL) await agent.killProcess(pid); ``` ```ts @nocheck server.ts import { agentOs } from "rivetkit/agent-os"; import { setup } from "rivetkit"; import common from "@rivet-dev/agent-os-common"; import pi from "@rivet-dev/agent-os-pi"; const vm = agentOs({ options: { software: [common, pi] }, }); export const registry = setup({ use: { vm } }); registry.start(); ``` ## System-wide process visibility View all processes across all VM runtimes, not just those started via `spawn`. ```ts @nocheck client.ts import { createClient } from "rivetkit/client"; import type { registry } from "./server"; const client = createClient("http://localhost:6420"); const agent = client.vm.getOrCreate(["my-agent"]); // All processes const all = await agent.allProcesses(); for (const p of all) { console.log(p.pid, p.driver, p.command, p.status); } // Process tree (parent-child hierarchy) const tree = await agent.processTree(); for (const node of tree) { console.log(node.pid, node.command, "children:", node.children.length); } ``` ```ts @nocheck server.ts import { agentOs } from "rivetkit/agent-os"; import { setup } from "rivetkit"; import common from "@rivet-dev/agent-os-common"; import pi from "@rivet-dev/agent-os-pi"; const vm = agentOs({ options: { software: [common, pi] }, }); export const registry = setup({ use: { vm } }); registry.start(); ``` ## Interactive shells Open an interactive shell with PTY support. Shell data is streamed via `shellData` events. ```ts @nocheck client.ts import { createClient } from "rivetkit/client"; import type { registry } from "./server"; const client = createClient("http://localhost:6420"); const agent = client.vm.getOrCreate(["my-agent"]); // Subscribe to shell output agent.on("shellData", (data) => { const text = new TextDecoder().decode(data.data); process.stdout.write(text); }); // Open a shell const { shellId } = await agent.openShell(); // Write commands to the shell await agent.writeShell(shellId, "ls -la /home/user\n"); // Resize the terminal await agent.resizeShell(shellId, 120, 40); // Close the shell when done await agent.closeShell(shellId); ``` ```ts @nocheck server.ts import { agentOs } from "rivetkit/agent-os"; import { setup } from "rivetkit"; import common from "@rivet-dev/agent-os-common"; import pi from "@rivet-dev/agent-os-pi"; const vm = agentOs({ options: { software: [common, pi] }, }); export const registry = setup({ use: { vm } }); registry.start(); ``` ## Recommendations - Use `exec` for short commands where you need the full output. Use `spawn` for long-running processes where you want streaming output. - Subscribe to `processOutput` and `processExit` **before** calling `spawn` to avoid missing events. - Active processes prevent the actor from sleeping. Stop or kill them when they are no longer needed. - Active shells also prevent sleep. Close shells when the user disconnects. - Use `allProcesses` and `processTree` for debugging. They show everything running in the VM, including agent processes. _Source doc path: /docs/agent-os/processes_