Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
cae85cb
docs(agentos): update docs for the 0.4 Core API
Oct 5, 2026
7493d43
docs(agentos): document the hosted VM v1 API
Oct 5, 2026
6265314
docs(agentos): install registry software from the release manifest
Oct 12, 2026
a0eab1e
docs(agentos): split library and hosted quickstarts, add Hosted VM HT…
Oct 12, 2026
6fd129e
docs(agentos): fix the Hosted VM HTTP API overview table header
Oct 12, 2026
3fde2e2
docs(agentos): title the quickstarts Quickstart (Library) and Quickst…
Oct 12, 2026
85998ec
docs(agentos): list the hosted quickstart before the library quickstart
Oct 12, 2026
5edf5c6
docs(agentos): show Hosted and Library examples as tabs, add Self-Hos…
Oct 12, 2026
aff3db5
docs(agentos): rename to Hosted HTTP API, add the comparison table to…
Oct 12, 2026
79078c1
docs(agentos): adopt the launch post's quickstart examples, note host…
Oct 12, 2026
09b1171
docs(agentos): TypeScript or HTTP to create a hosted VM, link and ren…
Oct 12, 2026
c727c22
docs(agentos): keep the hosted quickstart's Self-hosting step to a si…
Oct 12, 2026
08802c9
docs(agentos): reword the hosted vs library comparison table
Oct 12, 2026
9cbe27c
docs(agentos): trim quickstart intros, label HTTP examples HTTP
Oct 12, 2026
4892d72
docs(agentos): say durable instance in the comparison table
Oct 12, 2026
ee99051
docs(agentos): move Lifecycle under Runs in the comparison table
Oct 12, 2026
863f731
docs(agentos): put the library quickstart's install and create steps …
Oct 12, 2026
f079632
docs(agentos): drop the alpha contract note from the Hosted HTTP API
Oct 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/content/docs/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ title: "Architecture"
description: "How Core, the sidecar, kernel, VFS, and executors fit together."
---

`@rivet-dev/agentos-core` controls the same runtime from a trusted Node.js
process. It may retain host-only state such as callbacks, binding handlers,
mount plugins, local package paths, and custom scheduling.
`@rivet-dev/agentos-core` controls the runtime from a trusted Node.js process.
It may retain host-only state such as host function handlers, mount plugins,
local package paths, and custom scheduling.

## Runtime boundary

Expand All @@ -31,5 +31,5 @@ Each owner advances only its own migration ladder. There is no legacy storage
adoption path.

The default VM root is an ephemeral in-memory overlay over the bundled base
image. Configure durable filesystem storage for files that must survive VM
replacement.
image. Store the root filesystem in the VM's SQLite database for files that
must survive VM recreation; see [Persistence](/agentos/docs/persistence).
2 changes: 1 addition & 1 deletion docs/content/docs/architecture/filesystem.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Resolution is **longest-prefix wins**: if `/mnt/data` is a mount and the guest o
\- ...
```

The base layer is in-memory and per-VM; the runtime transparently persists it to backing storage so it survives sleep/wake. Mounts are pluggable: any guest path can be backed by the host, a remote, or a cloud store. See [Mounting filesystems](/agentos/docs/filesystem#mounts) for the user-facing config.
The base layer is in-memory and per-VM, and is discarded when the VM is disposed. A root or mount backed by the VM's SQLite database survives VM recreation; see [Persistence](/agentos/docs/persistence). Mounts are pluggable: any guest path can be backed by the host, a remote, or a cloud store. See [Mounting filesystems](/agentos/docs/filesystem#mounts) for the user-facing config.

## Routing a guest syscall

Expand Down
17 changes: 3 additions & 14 deletions docs/content/docs/architecture/networking.mdx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
title: "Networking"
description: "Explore the agentOS kernel socket table, JavaScript and WASM traffic, DNS, egress policy, loopback isolation, and preview routing."
description: "Explore the agentOS kernel socket table, JavaScript and WASM traffic, DNS, egress policy, and loopback isolation."
skill: true
---

<Note>These internal architecture docs are mostly generated and maintained by LLMs, then reviewed by humans. They are intentionally verbose; use your preferred LLM to ask focused questions about the architecture as needed.</Note>

This is the internals view of agentOS networking: the kernel socket table, the layers a request crosses, and where policy is enforced. For the user-facing API (`httpRequest`, preview URLs, the confinement model from a caller's perspective), see [Networking & Previews](/agentos/docs/networking). For the trust boundary this all sits inside, see [Architecture](/agentos/docs/architecture).
This is the internals view of agentOS networking: the kernel socket table, the layers a request crosses, and where policy is enforced. For the user-facing API (`httpRequest`, `fetch`, the confinement model from a caller's perspective), see [Networking](/agentos/docs/networking). For the trust boundary this all sits inside, see [Architecture](/agentos/docs/architecture).

The governing rule for TCP is that there is exactly **one authoritative transport for everything VM-local**: the kernel socket table. No untrusted guest code opens a host socket directly. Guest `fetch()`, `node:http`, TCP `node:net`, WASM TCP clients and servers, and host-into-guest requests (`httpRequest` / `rt.fetch`) all target the same listener table. The trusted sidecar implements `AF_UNIX` streams with a separate, per-VM private host transport while keeping pathname inodes and permissions authoritative in the guest VFS.

Expand Down Expand Up @@ -118,20 +118,9 @@ Every guest connect, listen, read, and write passes through sidecar ownership an

<Note>Host-to-guest requests bypass egress, not the table. `httpRequest` / `rt.fetch` terminate at the guest's loopback listener and never leave the VM, so they work even when guest egress (layer 3) or outbound `connect` (layer 1) is denied. They are host control-plane traffic, not guest egress, and only ever reach VM-owned listeners, while still going through the same kernel socket table as everything else.</Note>

## Preview URLs

A preview URL is port forwarding for a VM service: a time-limited, signed, publicly reachable URL that proxies HTTP to a port inside the VM. Mechanically it reuses the host-to-guest path:

- A signed token is minted for a `(VM, port)` pair with an expiration, capped by `preview.maxExpiresInSeconds`. Tokens are stored in SQLite, survive sleep/wake cycles, and expired ones are cleaned up automatically. Active tokens are bounded by `preview.maxActiveTokens` (1,024 by default); creation fails with a limit error that names the option when the bound is reached.
- An incoming request to the preview path is authenticated against the token, then proxied into the VM exactly like `httpRequest`: resolve the port to a VM-owned kernel listener, connect over loopback, frame HTTP/1.1, drive the target process, and return the bounded buffered response. The same fail-closed, VM-owned-listener-only rules apply.
- CORS is enabled so browsers can reach preview URLs from any origin.
- Revocation (`network.preview.expire`) invalidates the token immediately, after which the proxy refuses the request before touching the socket table.

Because previews ride the host fetch path, they are subject to loopback confinement at the kernel but **not** to the guest egress allowlist: the request enters the listener from the host side and never becomes guest outbound traffic.

## Where to go next

- [Networking & Previews](/agentos/docs/networking): the `httpRequest` and preview URL API, with usage examples.
- [Networking](/agentos/docs/networking): the `httpRequest` and `fetch` API, with usage examples.
- [JavaScript Executor & Socket Reactor](/agentos/docs/architecture/javascript-executor): how Tokio readiness wakes V8, how the channel lanes are separated, and how Node stream backpressure reaches the transport.
- [Architecture](/agentos/docs/architecture): the client / sidecar / executor trust boundary this stack lives inside.
- [Security Model](/agentos/docs/security-model): the full in-scope and out-of-scope threat model.
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ The shared Core package-source model is closed:

- `Url { url, expected_digest? }` downloads a remote artifact under strict
size, time, and redirect limits;
- `Path { path, expected_digest? }` reads a trusted local artifact and is
available only to embedded Core callers.
- `Path { path, expected_digest? }` reads a trusted local artifact from the
host.

The hosted actor accepts only `Url`. It cannot construct a host path, mount a
package from the host filesystem, or receive a custom resolver callback.
There is no custom resolver callback. A host that installs packages on behalf
of untrusted users should accept only `Url` sources from them.

Both variants verify the bytes before publishing them into the same
process-local content-addressed cache. Cache identity is the content digest,
not the URL. Installed packages are pinned while a VM generation uses them and
not the URL. Installed packages are pinned while a VM uses them and
otherwise participate in bounded LRU eviction.

## Command execution
Expand Down
26 changes: 13 additions & 13 deletions docs/content/docs/architecture/processes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ skill: true
<Note>These internal architecture docs are mostly generated and maintained by LLMs, then reviewed by humans. They are intentionally verbose; use your preferred LLM to ask focused questions about the architecture as needed.</Note>

This page is an internals deep-dive on the kernel's **process model**: the data
structures and syscall paths behind every guest process. For the client-facing
hosted API (`process.run`, `process.spawn`, `terminal.open`, lifecycle, the process tree), see
[Processes & Shell](/agentos/docs/processes). For the surrounding component and trust
structures and syscall paths behind every guest process. For the host-facing
API (`process.exec`, `process.spawn`, `terminal.open`, lifecycle, the process tree), see
[Processes & Shells](/agentos/docs/processes). For the surrounding component and trust
model, see [Architecture](/agentos/docs/architecture).

Two invariants frame everything below:
Expand All @@ -31,22 +31,22 @@ inside that VM; nothing in it corresponds to a host PID.

## How a spawn is serviced

A spawn, whether it originates from a client `spawn`/`run` call or from guest
A spawn, whether it originates from a host `spawn`/`exec` call or from guest
`node:child_process`, follows one path through the kernel:

1. **The request crosses into the kernel.** A client call arrives over the wire protocol; a guest call arrives as a syscall from the executor. Either way the kernel, not the caller, performs the work.
1. **The request crosses into the kernel.** A host call arrives over the sidecar protocol; a guest call arrives as a syscall from the executor. Either way the kernel, not the caller, performs the work.
2. **Permission check.** The kernel applies the VM's configured permission policy before doing anything. The policy is trusted input; the guest making the request is not.
3. **Resolve the program.** The command is resolved against the VM's virtual filesystem (PATH lookup over the VFS), not the host. The resolved program decides the driver: a JavaScript entrypoint runs in a V8 isolate; a `.wasm` program (including `sh` and coreutils) runs on the WASM runtime.
4. **Allocate the table entry.** The kernel assigns a virtual PID, records the command, arguments, environment, working directory, and parent PID, and links stdio endpoints (see below).
5. **Start execution.** The driver begins running the program. For a one-shot `run`, output and exit status are collected for the call's result; for `spawn`, the process remains available for explicit waiting and output replay.
6. **Reap and record exit.** When the program finishes, the kernel records the exit code on the table entry and marks it exited, which is what `process.wait` resolves against and what the `process.exit` event reports.
5. **Start execution.** The driver begins running the program. For a one-shot `exec`, output and exit status are collected for the call's result; for `spawn`, the process remains available for explicit waiting and output replay.
6. **Reap and record exit.** When the program finishes, the kernel records the exit code on the table entry and marks it exited, which is what `process.wait` resolves against and what `onProcessExit` reports.

Signals (`process.signal`) are the same shape: a request into the kernel, which
applies it to the virtualized process rather than to any host process.

## Process image replacement

Guest `execve` is distinct from the hosted one-shot `process.run` API. It
Guest `execve` is distinct from the host's one-shot `process.exec` API. It
replaces the current process image in place, following Linux process semantics:

- the virtual PID, parent, process group, session, working directory, pending signals, blocked-signal mask, stdio, and non-`FD_CLOEXEC` descriptors survive;
Expand All @@ -67,8 +67,8 @@ Standard streams are kernel-owned objects, not host file descriptors. Each
process entry has stdin, stdout, and stderr endpoints that the kernel wires up
when the entry is created.

- **Capture vs. stream.** `process.run` returns bounded stdout and stderr after the process exits. For `process.spawn`, the hosted actor exposes `process.output` events with generation-scoped process handles and bounded `process.output.read` replay; `process.exit` signals completion. Process and terminal replay use the same sidecar-owned retention and cursor implementation, so `maxEvents`, `maxBytes`, truncation, and progress behavior are identical across Rust Core and TypeScript Core. Events are low-latency hints; replay is the authoritative recovery path.
- **Writable stdin.** `process.stdin.write` pushes bytes into the process's stdin endpoint; `process.stdin.close` closes the write side so programs that read to EOF (like `cat`) can finish. None of this touches a real pipe on the host.
- **Capture vs. stream.** `process.exec` returns bounded stdout and stderr after the process exits. For `process.spawn`, `onProcessOutput` delivers live output and, when output retention is enabled, `process.readOutput` pages through bounded replay; `onProcessExit` signals completion. Replay uses a sidecar-owned retention and cursor implementation, so `maxEvents`, `maxBytes`, truncation, and progress behavior are identical across Rust Core and TypeScript Core. Events are low-latency hints; replay is the authoritative recovery path.
- **Writable stdin.** `process.writeStdin` pushes bytes into the process's stdin endpoint; `process.closeStdin` closes the write side so programs that read to EOF (like `cat`) can finish. None of this touches a real pipe on the host.
- **Pipes between processes.** Shell pipelines (`a | b`) connect one process's stdout endpoint to the next process's stdin endpoint through kernel-owned pipes. The pipe is a virtual object in the kernel, so a pipeline behaves like Linux without any host IPC.

Because these endpoints are kernel objects, the same bridging works identically
Expand All @@ -81,9 +81,9 @@ An interactive shell needs a terminal, not just piped stdio: line editing, job
control signals, and window size all depend on a PTY. The kernel provides
virtual PTY devices for this.

- **A shell is a process plus a PTY.** `terminal.open` allocates a kernel PTY and starts a shell process attached to it, returning a generation-scoped terminal handle. The PTY is a virtualized terminal device, never a host `/dev/pts` entry.
- **Bidirectional terminal I/O.** `terminal.stdin.write` feeds keystrokes into the PTY master side; output is available through `terminal.output` events and `terminal.output.read` replay. This carries terminal control sequences, so full-screen TUIs behave correctly.
- **Resize is a terminal operation.** `terminal.pty.resize` updates the PTY's window size (columns and rows), which the kernel propagates to the foreground process the way a real terminal resize would, so programs relying on `TIOCGWINSZ`-style sizing redraw correctly.
- **A shell is a process plus a PTY.** `terminal.open` allocates a kernel PTY and starts a shell process attached to it, returning a `shellId`. The PTY is a virtualized terminal device, never a host `/dev/pts` entry.
- **Bidirectional terminal I/O.** `terminal.write` feeds keystrokes into the PTY master side; output arrives through `onShellData`. This carries terminal control sequences, so full-screen TUIs behave correctly.
- **Resize is a terminal operation.** `terminal.resize` updates the PTY's window size (columns and rows), which the kernel propagates to the foreground process the way a real terminal resize would, so programs relying on `TIOCGWINSZ`-style sizing redraw correctly.
- **Teardown.** `terminal.close` tears down the PTY and the attached shell process. An open shell keeps the VM active, the same way an open PTY keeps a session alive on a real system.

## WASM sh and coreutils on the process model
Expand Down
63 changes: 63 additions & 0 deletions docs/content/docs/architecture/software-cache.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: "Software Installation and Preloading"
description: "Understand URL package installation, process caching, readiness, and preload coordination for hosted agentOS VMs."
---

Each VM projects installed packages as read-only filesystem leaves. The
projection is bounded by `config.limits.agentosPackages.maxMounts` (4,096 by
default), including command aliases and `provides.files` directory mounts.
Installing another package can fail with a resource-limit error even when the
download succeeded; the existing VM projection remains in place.

Hosted VMs install immutable `.aospkg` files from HTTPS URLs. Embedded Core
also accepts a trusted local file path. A hosted VM never receives or
materializes a host path.

## Resolution and projection

The resolver validates the URL, blocks ambient credentials and private network
destinations, bounds redirects and response headers, downloads into a temporary
file, verifies the optional SHA-256 digest, and validates the package format.
The verified content digest becomes the package identity.

The sidecar projects installed packages under
`/opt/agentos/pkgs/<name>/<version>` and command links under
`/opt/agentos/bin`. `v1.software.list` reads the current installed set.
`v1.software.install` and `v1.software.uninstall` are durable config mutations,
so they use the same revision checks and reconciliation as `v1.config.patch`.

## Process cache

All VMs in one worker process share the child sidecar's content-addressed
cache. Concurrent requests for the same digest are coalesced into one
acquisition. The cache is bounded by bytes, entries, active downloads, pending
downloads, and acquisition time. Live VM generations pin their package files.
Unpinned entries are evicted in least-recently-used order.

By default, each worker gets an isolated process-lifetime temporary cache. For
persistent recovery, set a distinct `AGENTOS_PACKAGE_CACHE_DIR` for each
concurrently running worker. An OS lock prevents startup recovery or eviction
from removing another worker's live package files. Restarting a worker with the
same directory recovers verified packages.

The services worker removes its temporary cache after normal shutdown or
startup failure. Forced termination or a host crash can leave temporary
directories behind; configure host temporary-directory cleanup for those
leftovers. Persistent directories are never removed at worker shutdown.

Partial downloads and failed publications use temporary files that are removed
when their operation is cancelled or fails. Package source URLs are kept only
as a short-lived bounded hint. Bytes are still verified before projection.

## Startup preloading

The `agentOS-preload-coordinator` is a central Rivet Actor that stores a
low-frequency popularity hint. It is not an authoritative registry or cache.
Each worker process reads one bounded plan at startup, coalesces that read for
the process, and warms likely package digests with bounded concurrency. The
default process warm deadline is 10 seconds.

Required packages still determine VM readiness. An advisory preload timeout or
coordinator failure only reduces the cache hit rate.

See [Software](/agentos/docs/software#install-while-running) for the installation API.
Loading
Loading