# Overview

agentOS runs AI agents and untrusted code safely inside fully virtualized Linux VMs. Nothing the guest does touches your host directly: there is no real host filesystem, no real host network socket, and no real host process. Every guest operation is serviced by a kernel that agentOS owns.

This page is a high-level tour. It walks through the overall shape, the parts that make up a VM, how agent sessions work, and the orchestration layer underneath. Each section links out to a detailed page when you want to go deeper.

## The big picture

A running agentOS system has three roles: your **app** (the client), your **server** (which runs the sidecar that hosts the VMs), and the **VM** where guest code actually runs. Your app never runs guest code itself, it asks the server to.

<svg viewBox="0 0 400 210" role="img" aria-label="A client (JavaScript, browser, or another backend) connects to an agentOS server. The server runs a sidecar that hosts many isolated VMs, each marked with the agentOS 'OS' logo; the sidecar brokers all guest syscalls and isolates each agent." style="width:100%;height:auto;max-width:420px;display:block;margin:2.5rem auto 0.5rem;">
  <defs>
    <marker id="bp-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M0,0 L10,5 L0,10 z" fill="#1b1916" />
    </marker>
    <symbol id="bp-os" viewBox="0 0 100 100">
      <rect x="8" y="8" width="84" height="84" rx="26" fill="none" stroke="#1b1916" stroke-width="8" />
      <text x="50" y="50" text-anchor="middle" dominant-baseline="central" font-family="var(--sl-font)" font-weight="700" font-size="38" fill="#1b1916">OS</text>
    </symbol>
  </defs>
  <rect x="12" y="67" width="140" height="60" rx="12" fill="#ffffff" stroke="#1b1916" stroke-width="1.5" />
  <text x="82" y="92" text-anchor="middle" font-family="var(--sl-font)" font-size="15" font-weight="600" fill="#1b1916">Client</text>
  <text x="82" y="112" text-anchor="middle" font-family="var(--sl-font)" font-size="10.5" fill="#56524a">JS · Browser · Backend</text>
  <line x1="154" y1="97" x2="205" y2="97" stroke="#1b1916" stroke-width="1.5" marker-end="url(#bp-arrow)" />
  <rect x="210" y="40" width="164" height="114" rx="14" fill="#faf8f3" stroke="#1b1916" stroke-width="1.5" />
  <text x="224" y="62" font-family="var(--sl-font)" font-size="13" font-weight="600" fill="#1b1916">Server</text>
  <g fill="#ffffff" stroke="#1b1916" stroke-width="1.2">
    <rect x="224" y="76" width="28" height="28" rx="5" />
    <rect x="260" y="76" width="28" height="28" rx="5" />
    <rect x="296" y="76" width="28" height="28" rx="5" />
    <rect x="332" y="76" width="28" height="28" rx="5" />
    <rect x="224" y="112" width="28" height="28" rx="5" />
    <rect x="260" y="112" width="28" height="28" rx="5" />
    <rect x="296" y="112" width="28" height="28" rx="5" />
    <rect x="332" y="112" width="28" height="28" rx="5" />
  </g>
  <g>
    <use href="#bp-os" x="229" y="81" width="18" height="18" />
    <use href="#bp-os" x="265" y="81" width="18" height="18" />
    <use href="#bp-os" x="301" y="81" width="18" height="18" />
    <use href="#bp-os" x="337" y="81" width="18" height="18" />
    <use href="#bp-os" x="229" y="117" width="18" height="18" />
    <use href="#bp-os" x="265" y="117" width="18" height="18" />
    <use href="#bp-os" x="301" y="117" width="18" height="18" />
    <use href="#bp-os" x="337" y="117" width="18" height="18" />
  </g>
  <g>
    <rect x="150" y="170" width="15" height="15" rx="4" fill="none" stroke="#56524a" stroke-width="1.4" />
    <text x="157.5" y="178" text-anchor="middle" dominant-baseline="central" font-family="var(--sl-font)" font-weight="700" font-size="7" fill="#56524a">OS</text>
    <text x="174" y="178" dominant-baseline="central" font-family="var(--sl-font)" font-size="12" fill="#56524a">= an isolated VM</text>
  </g>
</svg>

The client speaks to the agentOS server over the wire. The server runs the **sidecar**, the trusted core that hosts every VM: it owns each VM's kernel and brokers every guest syscall the agent makes (filesystem, processes, network, permissions) before carrying it out. Each VM is a fully isolated world, so agents are isolated from one another and from your host.

### Your app (the client)

- **Trusted caller.** Your app drives agentOS. It creates VMs, opens sessions, sends prompts, and reads results back.
- **Never runs guest code.** The agent and any code it generates run in the VM, not in your app's process.
- **Available everywhere.** There is a TypeScript client and a Rust client, and the same VM is reachable from a Node script, a browser/React app, or a separate backend.
- **Owns the configuration.** Everything you send (VM setup, permission policy, resource limits, mounts) is trusted input. See the [Security Model](/agentos/docs/security-model) for why your configuration is not an attack surface.

### Your server (the sidecar)

- **The trusted core.** The sidecar is the part of the system that owns everything: the kernel, the virtual filesystem, the process and socket tables, pipes, PTYs, the permission policy, and DNS.
- **The enforcement point.** Every request the VM makes is serviced here. The sidecar decides what is allowed before carrying it out.
- **Hosts every VM.** A single sidecar manages many VMs side by side, each with its own kernel, filesystem, and process table, so every agent runs in its own isolated world. A crash or runaway in one VM never affects another.

### The VM

- **A fully virtualized Linux environment.** Each VM has its own filesystem, process table, and network policy. Two VMs share nothing.
- **The unit of isolation.** Put one tenant or one task per VM to control the blast radius. A crash or runaway in one VM never affects another.
- **Where guest code lives.** The agent, the shell, npm packages, and any generated code all run inside the VM, behind the kernel's boundary.

## Anatomy of a Linux VM

Inside every VM there are two halves. The **kernel** is the trusted core that owns all the resources and rules. The **executor** is where untrusted guest code actually runs. Guest code can only *ask* the kernel for things, it never holds a real capability of its own.

<svg viewBox="0 0 700 360" role="img" aria-label="A VM split into a kernel and an executor. The kernel owns the virtual filesystem, process table, socket table, pipes, PTYs, DNS, and permission policy. The executor runs guest JavaScript, WASM, and native binaries, and reaches the kernel through syscalls." style="width:100%;height:auto;max-width:680px;display:block;margin:1.5rem auto 0.5rem;">
  <defs>
    <marker id="vm-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M0,0 L10,5 L0,10 z" fill="#1b1916" />
    </marker>
  </defs>
  <rect x="12" y="12" width="676" height="336" rx="14" fill="#faf8f3" stroke="#1b1916" stroke-width="1.5" />
  <text x="32" y="40" font-family="var(--sl-font)" font-size="13" font-weight="600" fill="#1b1916">The VM</text>

  <rect x="32" y="56" width="636" height="150" rx="10" fill="#ffffff" stroke="#1b1916" stroke-width="1.3" />
  <text x="52" y="82" font-family="var(--sl-font)" font-size="13" font-weight="600" fill="#1b1916">Kernel</text>
  <text x="52" y="100" font-family="var(--sl-font)" font-size="10.5" fill="#56524a">trusted core, every operation goes through here</text>
  <g font-family="var(--sl-font)" font-size="11" fill="#1b1916">
    <rect x="52" y="116" width="118" height="30" rx="6" fill="#faf8f3" stroke="#1b1916" stroke-width="1" /><text x="111" y="135" text-anchor="middle">virtual filesystem</text>
    <rect x="182" y="116" width="118" height="30" rx="6" fill="#faf8f3" stroke="#1b1916" stroke-width="1" /><text x="241" y="135" text-anchor="middle">process table</text>
    <rect x="312" y="116" width="118" height="30" rx="6" fill="#faf8f3" stroke="#1b1916" stroke-width="1" /><text x="371" y="135" text-anchor="middle">socket table</text>
    <rect x="442" y="116" width="92" height="30" rx="6" fill="#faf8f3" stroke="#1b1916" stroke-width="1" /><text x="488" y="135" text-anchor="middle">pipes / PTYs</text>
    <rect x="546" y="116" width="100" height="30" rx="6" fill="#faf8f3" stroke="#1b1916" stroke-width="1" /><text x="596" y="135" text-anchor="middle">DNS</text>
    <rect x="52" y="156" width="594" height="30" rx="6" fill="#faf8f3" stroke="#1b1916" stroke-width="1" /><text x="349" y="175" text-anchor="middle">permission policy · network allowlist · resource limits</text>
  </g>

  <line x1="349" y1="206" x2="349" y2="244" stroke="#1b1916" stroke-width="1.5" marker-end="url(#vm-arrow)" />
  <line x1="319" y1="244" x2="319" y2="206" stroke="#1b1916" stroke-width="1.5" marker-end="url(#vm-arrow)" />
  <text x="430" y="228" text-anchor="middle" font-family="var(--sl-font)" font-size="10" fill="#56524a">syscalls / replies</text>

  <rect x="32" y="248" width="636" height="84" rx="10" fill="#ffffff" stroke="#1b1916" stroke-width="1.3" />
  <text x="52" y="274" font-family="var(--sl-font)" font-size="13" font-weight="600" fill="#1b1916">Executor</text>
  <text x="52" y="292" font-family="var(--sl-font)" font-size="10.5" fill="#56524a">untrusted, runs guest code, holds no capabilities</text>
  <g font-family="var(--sl-font)" font-size="11" fill="#1b1916">
    <rect x="382" y="262" width="170" height="30" rx="6" fill="#faf8f3" stroke="#1b1916" stroke-width="1" /><text x="467" y="281" text-anchor="middle">guest JavaScript (native V8)</text>
    <rect x="562" y="262" width="84" height="30" rx="6" fill="#faf8f3" stroke="#1b1916" stroke-width="1" /><text x="604" y="281" text-anchor="middle">WASM</text>
    <rect x="382" y="298" width="264" height="22" rx="6" fill="#faf8f3" stroke="#1b1916" stroke-width="1" /><text x="514" y="313" text-anchor="middle" font-size="10.5">shell · coreutils · npm packages · native binaries</text>
  </g>
</svg>

### Kernel: the trusted core

<svg viewBox="0 0 480 150" role="img" aria-label="Guest requests funnel into a single kernel chokepoint, which fans out to its owned subsystems: filesystem, processes, network, and policy." style="width:100%;height:auto;max-width:440px;display:block;margin:2.5rem auto;">
  <defs>
    <marker id="kn-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M0,0 L10,5 L0,10 z" fill="#1b1916" />
    </marker>
  </defs>
  <rect x="14" y="58" width="92" height="34" rx="8" fill="#ffffff" stroke="#1b1916" stroke-width="1.3" />
  <text x="60" y="79" text-anchor="middle" font-family="var(--sl-font)" font-size="11" fill="#56524a">guest request</text>
  <line x1="106" y1="75" x2="150" y2="75" stroke="#1b1916" stroke-width="1.4" marker-end="url(#kn-arrow)" />
  <rect x="154" y="50" width="92" height="50" rx="10" fill="#faf8f3" stroke="#1b1916" stroke-width="1.4" />
  <text x="200" y="79" text-anchor="middle" font-family="var(--sl-font)" font-size="12" font-weight="600" fill="#1b1916">Kernel</text>
  <g font-family="var(--sl-font)" font-size="10" fill="#1b1916">
    <line x1="246" y1="60" x2="286" y2="22" stroke="#1b1916" stroke-width="1.2" marker-end="url(#kn-arrow)" />
    <line x1="246" y1="70" x2="286" y2="58" stroke="#1b1916" stroke-width="1.2" marker-end="url(#kn-arrow)" />
    <line x1="246" y1="80" x2="286" y2="92" stroke="#1b1916" stroke-width="1.2" marker-end="url(#kn-arrow)" />
    <line x1="246" y1="90" x2="286" y2="128" stroke="#1b1916" stroke-width="1.2" marker-end="url(#kn-arrow)" />
    <rect x="290" y="8" width="176" height="26" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="378" y="25" text-anchor="middle">filesystem</text>
    <rect x="290" y="46" width="176" height="26" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="378" y="63" text-anchor="middle">processes</text>
    <rect x="290" y="80" width="176" height="26" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="378" y="97" text-anchor="middle">network &amp; DNS</text>
    <rect x="290" y="116" width="176" height="26" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="378" y="133" text-anchor="middle">policy &amp; limits</text>
  </g>
</svg>

The kernel is the single chokepoint. Each kind of guest operation is serviced by a kernel-owned subsystem, never by a real host capability.

- **Virtual filesystem.** A per-VM filesystem. Guest reads and writes hit the VFS, not your host disk.
- **Process table.** A virtual process table. Child processes are kernel-managed and visible only inside their VM. No real host process is ever spawned for guest work.
- **Socket table and DNS.** A virtual network stack. Outbound traffic is gated by the network allowlist.
- **Pipes and PTYs.** Kernel-owned IPC and terminal devices, so shells and pipelines behave like real Linux.
- **Policy and limits.** The kernel checks the applied permission policy, network allowlist, and resource limits on every request.

### Executor: where guest code runs

<svg viewBox="0 0 480 130" role="img" aria-label="The untrusted executor runs guest JavaScript, WASM, and native binaries. It holds no capabilities and reaches the kernel through syscalls." style="width:100%;height:auto;max-width:440px;display:block;margin:2.5rem auto;">
  <defs>
    <marker id="ex-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M0,0 L10,5 L0,10 z" fill="#1b1916" />
    </marker>
  </defs>
  <rect x="14" y="14" width="300" height="102" rx="10" fill="#faf8f3" stroke="#1b1916" stroke-width="1.4" />
  <text x="30" y="36" font-family="var(--sl-font)" font-size="12" font-weight="600" fill="#1b1916">Executor</text>
  <text x="30" y="52" font-family="var(--sl-font)" font-size="9.5" fill="#56524a">untrusted · no capabilities</text>
  <g font-family="var(--sl-font)" font-size="10" fill="#1b1916">
    <rect x="30" y="62" width="80" height="44" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="70" y="88" text-anchor="middle">JS (V8)</text>
    <rect x="120" y="62" width="80" height="44" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="160" y="88" text-anchor="middle">WASM</text>
    <rect x="210" y="62" width="92" height="44" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="256" y="82" text-anchor="middle">native</text><text x="256" y="96" text-anchor="middle">binaries</text>
  </g>
  <line x1="314" y1="55" x2="358" y2="55" stroke="#1b1916" stroke-width="1.4" marker-end="url(#ex-arrow)" />
  <text x="336" y="48" text-anchor="middle" font-family="var(--sl-font)" font-size="9" fill="#56524a">syscall</text>
  <line x1="358" y1="75" x2="314" y2="75" stroke="#1b1916" stroke-width="1.4" marker-end="url(#ex-arrow)" />
  <text x="336" y="92" text-anchor="middle" font-family="var(--sl-font)" font-size="9" fill="#56524a">reply</text>
  <rect x="362" y="38" width="104" height="54" rx="10" fill="#ffffff" stroke="#1b1916" stroke-width="1.4" />
  <text x="414" y="70" text-anchor="middle" font-family="var(--sl-font)" font-size="12" font-weight="600" fill="#1b1916">Kernel</text>
</svg>

The executor is the untrusted half of the VM. It runs the guest code and reaches the kernel for everything else.

- **JavaScript Acceleration.** Guest JavaScript runs on a native V8 runtime (the same engine in Chrome and Node.js, with the full JIT compiler) inside an isolate. This is what we call **JavaScript Acceleration**: the guest's JavaScript executes at native speed, not through an interpreter or a translation shim. It is genuinely fast, and it presents normal Node.js semantics. See [JavaScript](/agentos/docs/javascript).
- **WASM alongside it.** The shell (`sh`) and the coreutils behind process execution ship as WebAssembly modules, and you can run your own WASM too. See [POSIX Syscalls](/agentos/docs/architecture/posix-syscalls) and the [Compiler Toolchain](/agentos/docs/architecture/compiler-toolchain).
- **Native binaries.** Tools mounted into the VM run inside the same boundary as everything else.
- **No host fallthrough.** The executor holds no capability of its own. For every file read, process spawn, or socket open, it issues a syscall and blocks for the kernel's reply.

### Processes & shell

<svg viewBox="0 0 480 120" role="img" aria-label="exec, run, and spawn create entries in the kernel-owned virtual process table, with stdio bridged through pipes and PTYs." style="width:100%;height:auto;max-width:440px;display:block;margin:2.5rem auto;">
  <defs>
    <marker id="pr-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M0,0 L10,5 L0,10 z" fill="#1b1916" />
    </marker>
  </defs>
  <g font-family="var(--sl-font)" font-size="11" fill="#1b1916">
    <rect x="14" y="14" width="92" height="26" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="60" y="31" text-anchor="middle">exec() / run()</text>
    <rect x="14" y="78" width="92" height="26" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="60" y="95" text-anchor="middle">spawn / shell</text>
  </g>
  <line x1="106" y1="27" x2="172" y2="52" stroke="#1b1916" stroke-width="1.3" marker-end="url(#pr-arrow)" />
  <line x1="106" y1="91" x2="172" y2="66" stroke="#1b1916" stroke-width="1.3" marker-end="url(#pr-arrow)" />
  <rect x="176" y="36" width="138" height="46" rx="10" fill="#faf8f3" stroke="#1b1916" stroke-width="1.4" />
  <text x="245" y="56" text-anchor="middle" font-family="var(--sl-font)" font-size="11.5" font-weight="600" fill="#1b1916">process table</text>
  <text x="245" y="71" text-anchor="middle" font-family="var(--sl-font)" font-size="9" fill="#56524a">virtual · per-VM</text>
  <line x1="314" y1="59" x2="360" y2="59" stroke="#1b1916" stroke-width="1.3" marker-end="url(#pr-arrow)" />
  <rect x="364" y="40" width="102" height="40" rx="8" fill="#ffffff" stroke="#1b1916" stroke-width="1.2" />
  <text x="415" y="64" text-anchor="middle" font-family="var(--sl-font)" font-size="10.5" fill="#1b1916">pipes &amp; PTYs</text>
</svg>

- **A real process model.** `exec()` and `run()` start fresh guest processes; you can also `spawn` long-running ones and open interactive shells.
- **Kernel-managed.** Every process lives in the virtual process table, with stdio bridged through kernel-owned pipes and PTYs.
- **Fresh each run.** Each `exec()` / `run()` starts a brand new guest process, so in-memory state never leaks from one run into the next.
- See [Processes](/agentos/docs/architecture/processes) for the internals.

### Virtual filesystem

<svg viewBox="0 0 480 150" role="img" aria-label="The virtual filesystem layers a writable overlay over a snapshot root, plus mount points that graft host directories, S3, or cloud stores onto guest paths." style="width:100%;height:auto;max-width:440px;display:block;margin:2.5rem auto;">
  <g font-family="var(--sl-font)" font-size="11" fill="#1b1916">
    <rect x="60" y="14" width="360" height="30" rx="8" fill="#ffffff" stroke="#1b1916" stroke-width="1.2" /><text x="240" y="33" text-anchor="middle">overlay (guest writes)</text>
    <rect x="60" y="52" width="360" height="30" rx="8" fill="#faf8f3" stroke="#1b1916" stroke-width="1.2" /><text x="240" y="71" text-anchor="middle">root layer (snapshot)</text>
  </g>
  <g font-family="var(--sl-font)" font-size="9.5" fill="#1b1916">
    <rect x="60" y="104" width="108" height="32" rx="7" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="114" y="124" text-anchor="middle">host dir mount</text>
    <rect x="186" y="104" width="108" height="32" rx="7" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="240" y="124" text-anchor="middle">S3 mount</text>
    <rect x="312" y="104" width="108" height="32" rx="7" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="366" y="124" text-anchor="middle">cloud store</text>
  </g>
  <text x="240" y="98" text-anchor="middle" font-family="var(--sl-font)" font-size="9" fill="#56524a">mount points grafted onto guest paths</text>
</svg>

- **Layered engines.** The VFS is a tree of engines: a root layer bootstrapped from a snapshot, an overlay for writes, and mount points that graft other backends onto guest paths.
- **Host-backed mounts.** A guest path can be backed by a host directory, S3, or a cloud store. The kernel confines all guest I/O to the mount root, even against symlink and `..` tricks.
- **Persisted.** The `/home/agentos` filesystem survives sleep/wake.
- See [Filesystem](/agentos/docs/architecture/filesystem) for the internals.

### Networking

<svg viewBox="0 0 480 150" role="img" aria-label="Guest fetch, node:http, node:net, and WASM sockets all converge on one kernel socket table, which gates outbound traffic through the network allowlist." style="width:100%;height:auto;max-width:440px;display:block;margin:2.5rem auto;">
  <defs>
    <marker id="nw-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M0,0 L10,5 L0,10 z" fill="#1b1916" />
    </marker>
  </defs>
  <g font-family="var(--sl-font)" font-size="10" fill="#1b1916">
    <rect x="14" y="10" width="92" height="24" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="60" y="26" text-anchor="middle">fetch()</text>
    <rect x="14" y="42" width="92" height="24" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="60" y="58" text-anchor="middle">node:http</text>
    <rect x="14" y="74" width="92" height="24" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="60" y="90" text-anchor="middle">node:net</text>
    <rect x="14" y="106" width="92" height="24" rx="6" fill="#ffffff" stroke="#1b1916" stroke-width="1" /><text x="60" y="122" text-anchor="middle">WASM sockets</text>
  </g>
  <line x1="106" y1="22" x2="186" y2="62" stroke="#1b1916" stroke-width="1.2" marker-end="url(#nw-arrow)" />
  <line x1="106" y1="54" x2="186" y2="66" stroke="#1b1916" stroke-width="1.2" marker-end="url(#nw-arrow)" />
  <line x1="106" y1="86" x2="186" y2="74" stroke="#1b1916" stroke-width="1.2" marker-end="url(#nw-arrow)" />
  <line x1="106" y1="118" x2="186" y2="78" stroke="#1b1916" stroke-width="1.2" marker-end="url(#nw-arrow)" />
  <rect x="190" y="48" width="116" height="44" rx="10" fill="#faf8f3" stroke="#1b1916" stroke-width="1.4" />
  <text x="248" y="68" text-anchor="middle" font-family="var(--sl-font)" font-size="11" font-weight="600" fill="#1b1916">socket table</text>
  <text x="248" y="83" text-anchor="middle" font-family="var(--sl-font)" font-size="9" fill="#56524a">kernel-owned</text>
  <line x1="306" y1="70" x2="350" y2="70" stroke="#1b1916" stroke-width="1.4" marker-end="url(#nw-arrow)" />
  <rect x="354" y="50" width="112" height="40" rx="8" fill="#ffffff" stroke="#1b1916" stroke-width="1.2" />
  <text x="410" y="74" text-anchor="middle" font-family="var(--sl-font)" font-size="10" fill="#1b1916">egress allowlist</text>
</svg>

- **One authoritative transport.** Guest `fetch()`, `node:http`, `node:net`, and WASM sockets all target the same kernel socket table. No part of guest networking opens a real host socket on its own.
- **Egress policy.** Outbound traffic is gated by the network allowlist; loopback traffic stays confined to the VM.
- **Preview URLs.** Servers a guest starts can be exposed through signed preview URLs.
- See [Networking](/agentos/docs/architecture/networking) for the internals.

> **NOTE:** The security boundary that matters is between the trusted sidecar and the untrusted executor. Everything the guest tries to do crosses into the kernel, where the policy is checked before the operation runs. See the [Security Model](/agentos/docs/security-model) for the full threat model.

## Agents & sessions

An agent (such as [Pi](https://github.com/mariozechner/pi-coding-agent)) is just another guest process running inside a VM, behind the same boundary as any other code. A **session** keeps that agent alive across many prompts and streams its output back to your app as events.

<svg viewBox="0 0 700 210" role="img" aria-label="A client sends a prompt to an agent running inside a VM. The agent streams events back to the client and persists a transcript." style="width:100%;height:auto;max-width:680px;display:block;margin:1.5rem auto 0.5rem;">
  <defs>
    <marker id="se-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M0,0 L10,5 L0,10 z" fill="#1b1916" />
    </marker>
  </defs>
  <rect x="12" y="66" width="150" height="78" rx="12" fill="#ffffff" stroke="#1b1916" stroke-width="1.5" />
  <text x="87" y="98" text-anchor="middle" font-family="var(--sl-font)" font-size="14" font-weight="600" fill="#1b1916">Client</text>
  <text x="87" y="118" text-anchor="middle" font-family="var(--sl-font)" font-size="10.5" fill="#56524a">your app</text>

  <line x1="162" y1="92" x2="266" y2="92" stroke="#1b1916" stroke-width="1.5" marker-end="url(#se-arrow)" />
  <text x="214" y="84" text-anchor="middle" font-family="var(--sl-font)" font-size="10" fill="#56524a">prompt</text>
  <line x1="266" y1="120" x2="162" y2="120" stroke="#1b1916" stroke-width="1.5" marker-end="url(#se-arrow)" />
  <text x="214" y="136" text-anchor="middle" font-family="var(--sl-font)" font-size="10" fill="#56524a">events</text>

  <rect x="270" y="30" width="280" height="150" rx="12" fill="#faf8f3" stroke="#1b1916" stroke-width="1.5" />
  <text x="290" y="56" font-family="var(--sl-font)" font-size="12" font-weight="600" fill="#1b1916">The VM</text>
  <rect x="300" y="72" width="220" height="56" rx="8" fill="#ffffff" stroke="#1b1916" stroke-width="1.2" />
  <text x="410" y="98" text-anchor="middle" font-family="var(--sl-font)" font-size="13" font-weight="600" fill="#1b1916">Agent session</text>
  <text x="410" y="116" text-anchor="middle" font-family="var(--sl-font)" font-size="10" fill="#56524a">long-lived agent process</text>

  <line x1="550" y1="105" x2="630" y2="105" stroke="#1b1916" stroke-width="1.5" marker-end="url(#se-arrow)" />
  <rect x="560" y="72" width="118" height="66" rx="10" fill="#ffffff" stroke="#1b1916" stroke-width="1.3" />
  <text x="619" y="100" text-anchor="middle" font-family="var(--sl-font)" font-size="12" font-weight="600" fill="#1b1916">Filesystem</text>
  <text x="619" y="118" text-anchor="middle" font-family="var(--sl-font)" font-size="10" fill="#56524a">SQLite over UDS</text>
</svg>

### Sessions & durable files

- **Long-lived.** Where a bare `exec()` runs once and exits, a session keeps an agent alive across many prompts.
- **Streamed.** The agent's output flows back to your app in real time as `sessionEvent`s.
- **Durable semantic events.** Completed ACP updates and interactive permission request/response records are sequenced in SQLite; streaming message deltas remain live-only.
- **Durable files.** Files under `/home/agentos` survive sleep through the sidecar's direct SQLite-over-UDS connection.
- **Context injected.** agentOS adds a system prompt describing the VM environment and available commands and bindings, layered on top of the agent's own instructions. See [System Prompt](/agentos/docs/system-prompt).
- See [Agent Sessions](/agentos/docs/architecture/agent-sessions) for the internals.

### Permissions & approvals

- **Two layers, different jobs.** The lower-level [permission policy](/agentos/docs/permissions) is enforced by the kernel on every guest syscall (nothing is allowed until you opt in). On top of that, [approvals](/agentos/docs/approvals) are about an agent asking before it uses a tool.
- **Human-in-the-loop or automatic.** Use the default `allow_all`, explicit `reject_all`, or subscribe to `permission_request` variants on the ordinary session-event stream with `permissionPolicy: "ask"`.
- **Blocks until answered.** An `ask` request has no expiry and keeps the active turn awake until a response or explicit lifecycle transition wins the race.

## Orchestration (Rivet Actors)

The `agentOS()` actor (from `@rivet-dev/agentos`) wraps the raw VM in a [Rivet Actor](/agentos/docs/core), which adds durable state, scheduling, and orchestration. This is what gives you persistence, cron, and workflows out of the box. It also registers the [inspector](/agentos/docs/inspector) tabs in the Rivet dashboard, so every actor comes with a live view of its transcript, filesystem, and processes.

<svg viewBox="0 0 700 200" role="img" aria-label="A Rivet Actor wraps an agentOS VM and adds durable state, cron scheduling, workflows, and sleep/wake persistence." style="width:100%;height:auto;max-width:680px;display:block;margin:1.5rem auto 0.5rem;">
  <rect x="40" y="20" width="620" height="160" rx="14" fill="#faf8f3" stroke="#1b1916" stroke-width="1.5" />
  <text x="64" y="46" font-family="var(--sl-font)" font-size="13" font-weight="600" fill="#1b1916">Rivet Actor</text>
  <text x="64" y="64" font-family="var(--sl-font)" font-size="10.5" fill="#56524a">durable, addressable server object</text>

  <rect x="64" y="80" width="180" height="80" rx="10" fill="#ffffff" stroke="#1b1916" stroke-width="1.3" />
  <text x="154" y="116" text-anchor="middle" font-family="var(--sl-font)" font-size="13" font-weight="600" fill="#1b1916">agentOS VM</text>
  <text x="154" y="136" text-anchor="middle" font-family="var(--sl-font)" font-size="10" fill="#56524a">the virtual Linux VM</text>

  <g font-family="var(--sl-font)" font-size="11.5" fill="#1b1916">
    <rect x="272" y="80" width="120" height="34" rx="7" fill="#ffffff" stroke="#1b1916" stroke-width="1.1" /><text x="332" y="102" text-anchor="middle">Cron</text>
    <rect x="412" y="80" width="120" height="34" rx="7" fill="#ffffff" stroke="#1b1916" stroke-width="1.1" /><text x="472" y="102" text-anchor="middle">Workflows</text>
    <rect x="272" y="126" width="260" height="34" rx="7" fill="#ffffff" stroke="#1b1916" stroke-width="1.1" /><text x="402" y="148" text-anchor="middle">Persistence · sleep / wake</text>
    <rect x="552" y="80" width="92" height="80" rx="7" fill="#ffffff" stroke="#1b1916" stroke-width="1.1" /><text x="598" y="116" text-anchor="middle">Durable</text><text x="598" y="132" text-anchor="middle">state</text>
  </g>
</svg>

### What are actors?

- **Durable server objects.** A Rivet Actor is a long-lived, addressable object with its own state. You reach a specific VM by name (`vm.getOrCreate("my-agent")`).
- **Stateful by default.** The actor persists its filesystem, actor state, durable session metadata, and completed ACP history. Active adapter processes remain runtime state.
- **The portable runtime.** Actors give you a consistent way to run `agentOS()` on any infrastructure, with persistence, networking, and orchestration built in.

### Cron

- **Recurring work.** Schedule a shell command or an agent session on a cron expression.
- **Overlap control.** Choose what happens when a run is still going when the next is due (`allow`, `skip`, or `queue`).
- **Observable.** Stream `cronEvent`s to watch executions. See [Crons & Loops](/agentos/docs/cron).

### Workflows

- **Durable multi-step tasks.** A workflow is the actor's `run` handler wrapped in `workflow()`, where each `ctx.step()` is recorded, retried, and resumed independently.
- **Crash-proof.** If the process dies mid-run, replay skips completed steps and continues where it left off.
- **Composable.** The output of one step feeds the next: clone a repo, let an agent fix a bug, run the tests. See [Workflows & Graphs](/agentos/docs/workflows).

### Persistence & sleep/wake

- **Sleeps when idle.** After a grace period (15 minutes by default) with no activity, the VM sleeps to free resources.
- **Wakes on demand.** It wakes automatically when a client connects or a cron job fires.
- **What survives.** The `/home/agentos` filesystem, actor state, preview tokens, durable session metadata, and completed ACP history persist. On wake, `openSession` restores the adapter when possible and otherwise starts it with AgentOS history as context. In-flight deltas, running processes, and open shells do not survive. See [Persistence & Sleep](/agentos/docs/persistence).

## Going deeper

This page is the map. Each subsystem has its own detailed page in the Advanced architecture section:

- **[Agent Sessions](/agentos/docs/architecture/agent-sessions)**: how a session is bound to a VM, and how prompts and events flow end to end.
- **[Processes](/agentos/docs/architecture/processes)**: the virtual process table, `exec()` / `run()`, child processes, and PTYs.
- **[Filesystem](/agentos/docs/architecture/filesystem)**: the per-VM virtual filesystem, overlays, and host-backed mounts.
- **[Networking](/agentos/docs/architecture/networking)**: the virtual socket table, DNS, the allowlist, and guest `fetch()`.
- **[JavaScript Executor & Socket Reactor](/agentos/docs/architecture/javascript-executor)**: how the shared Tokio runtime, V8 executor threads, coalesced readiness, bounded channels, and Node stream backpressure fit together.
- **[POSIX Syscalls](/agentos/docs/architecture/posix-syscalls)**: how WebAssembly guests behave like normal POSIX programs on top of the kernel.
- **[Compiler Toolchain](/agentos/docs/architecture/compiler-toolchain)**: how the shell and coreutils are compiled to WebAssembly and mounted into the VM.
- **[System Prompt](/agentos/docs/system-prompt)**: the context agentOS injects into every agent session.
- **[Persistence & Sleep](/agentos/docs/persistence)**: what survives sleep/wake, and how VMs sleep and wake.

For the trust model and what counts as a sandbox escape, see the [Security Model](/agentos/docs/security-model).
