Skip to main content
Executing Code

Long-Running Processes

Run servers, watchers, and other background processes in Secure Exec with spawn, and reach them from the host.

execute and evaluate wait for your code to finish, so a server started that way runs until timeoutMs and returns timed_out. For code that is meant to keep running, spawn it in a VM.

Spawn a background process

spawn returns as soon as the process is running.

import { createVm } from "secure-exec";

// The server is user-authored code, so it runs in a VM. Guest listeners stay on
// the VM's virtual network and do not need external network access.
const vm = await createVm();

// `spawn` returns as soon as the process starts, instead of waiting for the
// code to finish. The server prints a line once it is listening, so the host
// knows when it can send requests.
const ready = Promise.withResolvers<void>();
const decoder = new TextDecoder();
const server = await vm.javascript.spawn(
	`
	import { createServer } from "node:http";

	createServer((request, response) => {
		response.setHeader("content-type", "application/json");
		response.end(JSON.stringify({ path: request.url, pid: process.pid }));
	}).listen(3000, () => console.log("listening"));
	`,
	{
		onStdout: (chunk) => {
			if (decoder.decode(chunk).includes("listening")) ready.resolve();
		},
	},
);
console.log("server pid:", server.pid);
await ready.promise;

vm.typescript.spawn does the same for TypeScript source, and spawnFile for a file that is already in the VM.

What a spawned process shares

A spawned process is its own program in the VM, like a process on Linux.

Shared with everything else in the VMNot shared
The filesystem, including files you write from the hostJavaScript memory, including any context
Installed npm packages
The virtual network, so other code in the VM can reach its ports

Other calls keep working while it runs. Code in the same VM can reach the process on 127.0.0.1, which makes a spawned server a good home for state that several calls or contexts need to share.

Reach it from the host

vm.network.httpRequest sends a request to a port inside the VM. Nothing is exposed on the host’s own network.

// Send requests from the host to the port inside the VM. Nothing is exposed on
// the host's own network.
const response = await vm.network.httpRequest({ port: 3000, path: "/hello" });
console.log(new TextDecoder().decode(response.body)); // {"path":"/hello","pid":...}

Manage the process

vm.process controls processes by pid.

// Stop the server, then dispose the VM.
await vm.process.kill(server.pid);
const exit = await vm.process.wait(server.pid);
console.log("server exited:", exit);
await vm.dispose();

wait(pid) resolves when the process exits, kill(pid) and signal(pid, signal) stop it, and list() shows what is running. onStdout and onStderr on spawn stream its output live. Stop spawned processes before you dispose the VM.

Read the agentOS processes docs for the full process model.

Edit this page Last updated September 21, 2026