diff --git a/docs/design/agentos-apps-api-simplification.md b/docs-internal/design/agentos-apps-api-simplification.md similarity index 100% rename from docs/design/agentos-apps-api-simplification.md rename to docs-internal/design/agentos-apps-api-simplification.md diff --git a/docs/design/agentos-apps-packaging.md b/docs-internal/design/agentos-apps-packaging.md similarity index 100% rename from docs/design/agentos-apps-packaging.md rename to docs-internal/design/agentos-apps-packaging.md diff --git a/docs/design/agentos-apps.md b/docs-internal/design/agentos-apps.md similarity index 100% rename from docs/design/agentos-apps.md rename to docs-internal/design/agentos-apps.md diff --git a/docs/design/execution-api-redesign.md b/docs-internal/design/execution-api-redesign.md similarity index 100% rename from docs/design/execution-api-redesign.md rename to docs-internal/design/execution-api-redesign.md diff --git a/docs/design/execution-retention-and-output.md b/docs-internal/design/execution-retention-and-output.md similarity index 100% rename from docs/design/execution-retention-and-output.md rename to docs-internal/design/execution-retention-and-output.md diff --git a/docs/design/language-execution-api.md b/docs-internal/design/language-execution-api.md similarity index 100% rename from docs/design/language-execution-api.md rename to docs-internal/design/language-execution-api.md diff --git a/docs/design/unified-sidecar-runtime.md b/docs-internal/design/unified-sidecar-runtime.md similarity index 100% rename from docs/design/unified-sidecar-runtime.md rename to docs-internal/design/unified-sidecar-runtime.md diff --git a/docs/features/typescript.mdx b/docs-internal/features/typescript.mdx similarity index 100% rename from docs/features/typescript.mdx rename to docs-internal/features/typescript.mdx diff --git a/docs/filesystem.mdx b/docs-internal/filesystem.mdx similarity index 100% rename from docs/filesystem.mdx rename to docs-internal/filesystem.mdx diff --git a/docs/node-compatibility-status.md b/docs-internal/node-compatibility-status.md similarity index 100% rename from docs/node-compatibility-status.md rename to docs-internal/node-compatibility-status.md diff --git a/docs/system-drivers/browser.mdx b/docs-internal/system-drivers/browser.mdx similarity index 100% rename from docs/system-drivers/browser.mdx rename to docs-internal/system-drivers/browser.mdx diff --git a/docs/thin-client-research/item-93-implementation.md b/docs-internal/thin-client-research/item-93-implementation.md similarity index 100% rename from docs/thin-client-research/item-93-implementation.md rename to docs-internal/thin-client-research/item-93-implementation.md diff --git a/docs/thin-client-research/item-94-implementation.md b/docs-internal/thin-client-research/item-94-implementation.md similarity index 100% rename from docs/thin-client-research/item-94-implementation.md rename to docs-internal/thin-client-research/item-94-implementation.md diff --git a/docs/wasmvm/supported-commands.md b/docs-internal/wasmvm/supported-commands.md similarity index 100% rename from docs/wasmvm/supported-commands.md rename to docs-internal/wasmvm/supported-commands.md diff --git a/docs/AGENTS.md b/docs/AGENTS.md new file mode 120000 index 0000000000..681311eb9c --- /dev/null +++ b/docs/AGENTS.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md new file mode 100644 index 0000000000..2d6ae04c2c --- /dev/null +++ b/docs/CLAUDE.md @@ -0,0 +1,125 @@ +# Docs Bundle CLAUDE.md + +Rules for the docs in this repo. These pages are **not** rendered here — they are +published on [rivet.dev](https://rivet.dev) by the +[rivet-website](https://github.com/rivet-dev/website) repo, which symlinks +this directory in. Everything below exists so a page written here renders +correctly there. + +## Layout + +``` +docs/ + sidebar.json navigation for the two tabs + content/ + docs/**.mdx -> /{product}/docs/... + tutorials/**.mdx -> /{product}/tutorials/... +``` + +The website links `docs/content` into its content collection, so **only real +pages belong under `content/`**. Anything else (scripts, fixtures, notes) goes +elsewhere in the repo or it will be published as a docs page. + +## Frontmatter + +Every page needs `title` and `description`. Both are used for SEO and the +sidebar falls back to `title` when a sidebar entry omits one. + +```mdx +--- +title: "In-Memory State" +description: "Actors store state in memory for instant reads and writes." +--- +``` + +## sidebar.json + +Navigation for this product's Documentation and Tutorials tabs. Icons travel as +Font Awesome **export names**, not objects, so this repo needs no dependency on +the website's icon package. + +```json +{ + "docs": [ + { "title": "General", "pages": [ + { "title": "Introduction", "href": "/actors/docs", "icon": "faSquareInfo" } + ]} + ], + "tutorials": [] +} +``` + +- `href` is the full site path, including the product segment. +- Adding a page to `content/` does not add it to the nav. Add it here too. +- The Self-Host tab is **not** in this file. It is generated by the website. + +## Code + +- **Never inline a fenced TypeScript block.** Real examples live in `examples/` + and are embedded with ``, so they are type-checked and cannot rot. + A snippet that fails to compile fails the website build. +- Snippet paths are relative to **this repo's root**, so the same path works both + here and on rivet.dev: + ```mdx + + ``` +- Embed part of a file with `region="name"`, delimited in the source by + `// docs:start name` / `// docs:end name`. +- Shell commands, YAML, Dockerfiles, and terminal output **may** be inline fenced + blocks. The no-inline rule exists for type checking, which only applies to + TypeScript. +- Every TypeScript snippet must include its imports and define everything it + references. Use `@nocheck` only for API that does not exist on this branch yet. +- Use `` for examples spanning multiple files, with each + file as its own ``. + +## What does not belong here + +- **Marketing pages.** They live in the website repo. +- **Deploy and self-hosting guides.** They are written once in the website repo + and templated across every product. Do not write a per-product copy. +- **Website components.** Do not import from the website by relative path or + alias; a page must render from the components the site already provides. + +## Terminology + +Applies to everything published on the website. + +- The service that routes, schedules, and persists is the **control plane**. + Never "engine", "server", or "orchestrator". +- A process running user code with the Rivet SDK is a **worker**. Never "envoy", + "runner", "node", "compute", or "data plane". +- **Never use "agent" as a deployment noun.** Rivet ships agentOS and Actors is + "where agents live"; the collision is unrecoverable. +- **"envoy" never appears in docs.** Envoy Proxy is a top-tier CNCF project. + Internal code keeps its own names. +- **"Rivet Compute" is retired.** Where prose must name the managed offering it + is **Rivet Cloud**, and it links to . +- Spell the product `agentOS`, never `AgentOS`. Capitalize **Rivet Actor** as a + proper noun, lowercase generic "actor". +- Always `rivet.dev`, never `rivet.gg`. + +## Writing + +- Write comments and prose as complete sentences. **Never use em dashes**; use + periods instead. +- Do not document deltas. A reader who never saw the old version gains nothing + from "this was renamed". + +## Previewing locally + +Clone the website next to this repo and run it. It detects the sibling +automatically and serves this directory's pages live: + +```sh +git clone https://github.com/rivet-dev/website +cd rivet-website && pnpm install && pnpm dev +``` + +`pnpm assemble` prints which checkout each product resolved to. To point at a +different checkout, repoint the symlink; it is gitignored and assemble leaves an +existing one alone: + +```sh +ln -sfn /path/to/this/repo/docs/content src/content/docs/ +``` diff --git a/website/src/content/docs/docs/agent-to-agent.mdx b/docs/content/docs/agent-to-agent.mdx similarity index 84% rename from website/src/content/docs/docs/agent-to-agent.mdx rename to docs/content/docs/agent-to-agent.mdx index 9f964103a1..78a10e7b77 100644 --- a/website/src/content/docs/docs/agent-to-agent.mdx +++ b/docs/content/docs/agent-to-agent.mdx @@ -4,7 +4,7 @@ description: "Use bindings to let agents communicate with each other." skill: true --- -Agents communicate through [bindings](/docs/bindings). You define a bindings group that lets one agent send work to another, and the agent calls it like any other CLI command. +Agents communicate through [bindings](/agentos/docs/bindings). You define a bindings group that lets one agent send work to another, and the agent calls it like any other CLI command. ## Example: code writer + reviewer @@ -34,4 +34,4 @@ Bindings are the natural communication layer between agents because: ## Recommendations - Each agent has its own isolated VM and filesystem (they share no filesystem). Pass file contents through the binding input, then use `writeFile` in the binding to land them in the other VM. -- Use [Workflows](/docs/workflows) to make multi-agent pipelines durable across restarts. +- Use [Workflows](/agentos/docs/workflows) to make multi-agent pipelines durable across restarts. diff --git a/website/src/content/docs/docs/agents/claude.mdx b/docs/content/docs/agents/claude.mdx similarity index 86% rename from website/src/content/docs/docs/agents/claude.mdx rename to docs/content/docs/agents/claude.mdx index aa0181b2d8..43bce8d53b 100644 --- a/website/src/content/docs/docs/agents/claude.mdx +++ b/docs/content/docs/agents/claude.mdx @@ -12,7 +12,7 @@ skill: false -Read [Sessions](/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. +Read [Sessions](/agentos/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. ## Model & credentials @@ -25,7 +25,7 @@ Set the relevant variable(s) on the session's `env`, sourced from your server's - `CLAUDE_CODE_USE_BEDROCK=1` — use Amazon Bedrock (auth via the AWS credential chain: `AWS_REGION`, `AWS_PROFILE`, …). - `CLAUDE_CODE_USE_VERTEX=1` — use Google Vertex AI (auth via Google Cloud credentials). -See [Models & Credentials](/docs/models-and-credentials), and Claude Code's [environment variables](https://code.claude.com/docs/en/env-vars) for the full list. +See [Models & Credentials](/agentos/docs/models-and-credentials), and Claude Code's [environment variables](https://code.claude.com/docs/en/env-vars) for the full list. ## Skills @@ -45,4 +45,4 @@ Expose extra tools to the agent by passing `mcpServers` to `openSession`. Both l ## Customizing the agent -Claude Code is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked build as a new agent, see [Custom Agents](/docs/agents/custom). +Claude Code is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked build as a new agent, see [Custom Agents](/agentos/docs/agents/custom). diff --git a/website/src/content/docs/docs/agents/codex.mdx b/docs/content/docs/agents/codex.mdx similarity index 85% rename from website/src/content/docs/docs/agents/codex.mdx rename to docs/content/docs/agents/codex.mdx index 852af14ee0..0010acd417 100644 --- a/website/src/content/docs/docs/agents/codex.mdx +++ b/docs/content/docs/agents/codex.mdx @@ -11,7 +11,7 @@ skill: false -Read [Sessions](/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. +Read [Sessions](/agentos/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. ## Model & credentials @@ -21,7 +21,7 @@ Set the relevant variable(s) on the session's `env`, sourced from your server's - `OPENAI_BASE_URL` — route through a gateway or OpenAI-compatible endpoint. - Custom providers — defined in `~/.codex/config.toml`; each provider's `env_key` names the variable Codex reads for its key (e.g. `AZURE_OPENAI_API_KEY`, `MISTRAL_API_KEY`). -See [Models & Credentials](/docs/models-and-credentials), and Codex's [config reference](https://developers.openai.com/codex/config-reference) for details. +See [Models & Credentials](/agentos/docs/models-and-credentials), and Codex's [config reference](https://developers.openai.com/codex/config-reference) for details. ## Skills @@ -41,4 +41,4 @@ Expose extra tools to the agent by passing `mcpServers` to `openSession`. Both l ## Customizing the agent -Codex is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked build as a new agent, see [Custom Agents](/docs/agents/custom). +Codex is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked build as a new agent, see [Custom Agents](/agentos/docs/agents/custom). diff --git a/website/src/content/docs/docs/agents/custom.mdx b/docs/content/docs/agents/custom.mdx similarity index 87% rename from website/src/content/docs/docs/agents/custom.mdx rename to docs/content/docs/agents/custom.mdx index 9e82e8beb8..8b9cd72292 100644 --- a/website/src/content/docs/docs/agents/custom.mdx +++ b/docs/content/docs/agents/custom.mdx @@ -84,15 +84,15 @@ export const registry = setup({ use: { vm } }); registry.start(); ``` -See [Sessions](/docs/sessions) for creating and driving sessions. Package your adapter with `agentos-toolchain pack --agent my-agent-acp` so its dependencies are bundled into the self-contained package directory and the `agent` block (naming the `bin/` ACP entrypoint) is written into the package's `agentos-package.json`, rather than shipping it as a loose file. +See [Sessions](/agentos/docs/sessions) for creating and driving sessions. Package your adapter with `agentos-toolchain pack --agent my-agent-acp` so its dependencies are bundled into the self-contained package directory and the `agent` block (naming the `bin/` ACP entrypoint) is written into the package's `agentos-package.json`, rather than shipping it as a loose file. All built-in agents are defined exactly this way. Browse them for reference on [GitHub](https://github.com/rivet-dev/agentos/tree/main/software). ## Read more -- [Defining software packages](/docs/custom-software/definition): the full descriptor reference, including the `agentos-package.json` schema and every `agent` field (`acpEntrypoint`, `env`, `launchArgs`, `snapshot`). -- [Building binaries](/docs/custom-software/building-wasm): compile WASM command binaries and use the registry. +- [Defining software packages](/agentos/docs/custom-software/definition): the full descriptor reference, including the `agentos-package.json` schema and every `agent` field (`acpEntrypoint`, `env`, `launchArgs`, `snapshot`). +- [Building binaries](/agentos/docs/custom-software/building-wasm): compile WASM command binaries and use the registry. ## Debugging -When a custom agent exits mid-turn or a tool call fails, capture the agent's stderr with the `onAgentStderr` hook on `AgentOs.create()`. The agent uses stdout for ACP, so stderr carries its logs and crash output. See [Debugging](/docs/debugging) for that hook and the runtime (sidecar) logs. +When a custom agent exits mid-turn or a tool call fails, capture the agent's stderr with the `onAgentStderr` hook on `AgentOs.create()`. The agent uses stdout for ACP, so stderr carries its logs and crash output. See [Debugging](/agentos/docs/debugging) for that hook and the runtime (sidecar) logs. diff --git a/website/src/content/docs/docs/agents/opencode.mdx b/docs/content/docs/agents/opencode.mdx similarity index 91% rename from website/src/content/docs/docs/agents/opencode.mdx rename to docs/content/docs/agents/opencode.mdx index 857fc084d2..41297c1447 100644 --- a/website/src/content/docs/docs/agents/opencode.mdx +++ b/docs/content/docs/agents/opencode.mdx @@ -12,7 +12,7 @@ skill: false -Read [Sessions](/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. +Read [Sessions](/agentos/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. ## Model & credentials @@ -25,7 +25,7 @@ OpenCode auto-detects a provider when its key is present on the session's `env`, - `GROQ_API_KEY` — Groq. - …plus Amazon Bedrock, Azure, Google Vertex, and 70+ providers via [models.dev](https://models.dev). -See [Models & Credentials](/docs/models-and-credentials), and OpenCode's [providers docs](https://opencode.ai/docs/providers/) for the full list. +See [Models & Credentials](/agentos/docs/models-and-credentials), and OpenCode's [providers docs](https://opencode.ai/docs/providers/) for the full list. ## Model configuration @@ -76,4 +76,4 @@ Expose extra tools to the agent by passing `mcpServers` to `openSession`. Both l ## Customizing the agent -OpenCode is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked build as a new agent, see [Custom Agents](/docs/agents/custom). +OpenCode is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked build as a new agent, see [Custom Agents](/agentos/docs/agents/custom). diff --git a/website/src/content/docs/docs/agents/pi.mdx b/docs/content/docs/agents/pi.mdx similarity index 87% rename from website/src/content/docs/docs/agents/pi.mdx rename to docs/content/docs/agents/pi.mdx index dc9d49ebab..674b433e50 100644 --- a/website/src/content/docs/docs/agents/pi.mdx +++ b/docs/content/docs/agents/pi.mdx @@ -12,7 +12,7 @@ skill: true -Read [Sessions](/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. +Read [Sessions](/agentos/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. ## Model & credentials @@ -21,7 +21,7 @@ Set the relevant variable on the session's `env`, sourced from your server's env - `ANTHROPIC_API_KEY` — Anthropic (Claude), the default. - Other providers — use the provider-named key (e.g. `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`). -See [Models & Credentials](/docs/models-and-credentials), and Pi's [providers docs](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/providers.md) for the full list. +See [Models & Credentials](/agentos/docs/models-and-credentials), and Pi's [providers docs](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/providers.md) for the full list. ## Skills @@ -56,4 +56,4 @@ See the [Pi extension documentation](https://github.com/badlogic/pi-mono/tree/ma ## Customizing the agent -Pi is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked Pi build as a new agent, see [Custom Agents](/docs/agents/custom). +Pi is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked Pi build as a new agent, see [Custom Agents](/agentos/docs/agents/custom). diff --git a/website/src/content/docs/docs/approvals.mdx b/docs/content/docs/approvals.mdx similarity index 100% rename from website/src/content/docs/docs/approvals.mdx rename to docs/content/docs/approvals.mdx diff --git a/website/src/content/docs/docs/architecture.mdx b/docs/content/docs/architecture.mdx similarity index 91% rename from website/src/content/docs/docs/architecture.mdx rename to docs/content/docs/architecture.mdx index ea7d78b2e0..527df1fd13 100644 --- a/website/src/content/docs/docs/architecture.mdx +++ b/docs/content/docs/architecture.mdx @@ -62,7 +62,7 @@ The client speaks to the agentOS server over the wire. The server runs the **sid - **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](/docs/security-model) for why your configuration is not an attack surface. +- **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) @@ -174,8 +174,8 @@ The kernel is the single chokepoint. Each kind of guest operation is serviced by 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](/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](/docs/architecture/posix-syscalls) and the [Compiler Toolchain](/docs/architecture/compiler-toolchain). +- **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. @@ -204,7 +204,7 @@ The executor is the untrusted half of the VM. It runs the guest code and reaches - **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](/docs/architecture/processes) for the internals. +- See [Processes](/agentos/docs/architecture/processes) for the internals. ### Virtual filesystem @@ -224,7 +224,7 @@ The executor is the untrusted half of the VM. It runs the guest code and reaches - **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](/docs/architecture/filesystem) for the internals. +- See [Filesystem](/agentos/docs/architecture/filesystem) for the internals. ### Networking @@ -255,9 +255,9 @@ The executor is the untrusted half of the VM. It runs the guest code and reaches - **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](/docs/architecture/networking) for the internals. +- See [Networking](/agentos/docs/architecture/networking) for the internals. -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](/docs/security-model) for the full threat model. +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 @@ -296,18 +296,18 @@ An agent (such as [Pi](https://github.com/mariozechner/pi-coding-agent)) is just - **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](/docs/system-prompt). -- See [Agent Sessions](/docs/architecture/agent-sessions) for the internals. +- **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](/docs/permissions) is enforced by the kernel on every guest syscall (nothing is allowed until you opt in). On top of that, [approvals](/docs/approvals) are about an agent asking before it uses a tool. +- **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](/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](/docs/inspector) tabs in the Rivet dashboard, so every actor comes with a live view of its transcript, filesystem, and processes. +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. @@ -336,32 +336,32 @@ The `agentOS()` actor (from `@rivet-dev/agentos`) wraps the raw VM in a [Rivet A - **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](/docs/cron). +- **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](/docs/workflows). +- **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](/docs/persistence). +- **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](/docs/architecture/agent-sessions)**: how a session is bound to a VM, and how prompts and events flow end to end. -- **[Processes](/docs/architecture/processes)**: the virtual process table, `exec()` / `run()`, child processes, and PTYs. -- **[Filesystem](/docs/architecture/filesystem)**: the per-VM virtual filesystem, overlays, and host-backed mounts. -- **[Networking](/docs/architecture/networking)**: the virtual socket table, DNS, the allowlist, and guest `fetch()`. -- **[JavaScript Executor & Socket Reactor](/docs/architecture/javascript-executor)**: how the shared Tokio runtime, V8 executor threads, coalesced readiness, bounded channels, and Node stream backpressure fit together. -- **[POSIX Syscalls](/docs/architecture/posix-syscalls)**: how WebAssembly guests behave like normal POSIX programs on top of the kernel. -- **[Compiler Toolchain](/docs/architecture/compiler-toolchain)**: how the shell and coreutils are compiled to WebAssembly and mounted into the VM. -- **[System Prompt](/docs/system-prompt)**: the context agentOS injects into every agent session. -- **[Persistence & Sleep](/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](/docs/security-model). +- **[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). diff --git a/website/src/content/docs/docs/architecture/agent-sdk-snapshots.mdx b/docs/content/docs/architecture/agent-sdk-snapshots.mdx similarity index 85% rename from website/src/content/docs/docs/architecture/agent-sdk-snapshots.mdx rename to docs/content/docs/architecture/agent-sdk-snapshots.mdx index 7f56b87e1c..4f0f916bf9 100644 --- a/website/src/content/docs/docs/architecture/agent-sdk-snapshots.mdx +++ b/docs/content/docs/architecture/agent-sdk-snapshots.mdx @@ -6,11 +6,11 @@ skill: true 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. -This page is an internals deep-dive on **agent SDK snapshotting** — an optional optimization that loads an agent's SDK *once per sidecar* and reuses it for every session, instead of re-evaluating the whole SDK module graph on each `openSession`. For the agent-author view (how to opt in and the rules your SDK must follow), see [Software Definition → SDK snapshotting & snapshot-safety](/docs/custom-software/definition). For how sessions work in general, see [Agent Sessions](/docs/architecture/agent-sessions). +This page is an internals deep-dive on **agent SDK snapshotting** — an optional optimization that loads an agent's SDK *once per sidecar* and reuses it for every session, instead of re-evaluating the whole SDK module graph on each `openSession`. For the agent-author view (how to opt in and the rules your SDK must follow), see [Software Definition → SDK snapshotting & snapshot-safety](/agentos/docs/custom-software/definition). For how sessions work in general, see [Agent Sessions](/agentos/docs/architecture/agent-sessions). ## The problem: per-session SDK re-evaluation -When a session starts, its agent adapter runs inside a fresh [V8 isolate](/docs/architecture/agent-sessions) and imports the agent SDK (for Pi, `@mariozechner/pi-coding-agent`). Importing a real-world SDK means resolving, loading, compiling, and **evaluating** a large module graph — hundreds of modules running their top-level initialization. That evaluation dominates session-creation latency, and because every session gets a fresh isolate, it is paid *again on every `openSession`*. +When a session starts, its agent adapter runs inside a fresh [V8 isolate](/agentos/docs/architecture/agent-sessions) and imports the agent SDK (for Pi, `@mariozechner/pi-coding-agent`). Importing a real-world SDK means resolving, loading, compiling, and **evaluating** a large module graph — hundreds of modules running their top-level initialization. That evaluation dominates session-creation latency, and because every session gets a fresh isolate, it is paid *again on every `openSession`*. The work is identical every time: the same modules, evaluated to the same post-init heap, only to be thrown away when the session ends. Snapshotting captures that post-init heap once and stamps it into every new isolate. @@ -22,10 +22,10 @@ Agent SDK snapshotting extends that same mechanism: it evaluates the agent SDK * ## Where it sits in the component model -The [three components](/docs/architecture#the-big-picture) are unchanged. Snapshotting only changes *how* the executor's isolate is seeded: +The [three components](/agentos/docs/architecture#the-big-picture) are unchanged. Snapshotting only changes *how* the executor's isolate is seeded: - **Client.** Builds the SDK bundle at package-build time and passes it to the sidecar as trusted VM configuration (`jsRuntime.snapshotUserlandCode`). It decides which agents opt in. -- **Sidecar.** Owns the snapshot. It builds the snapshot once, caches it process-wide, and seeds each session's isolate from it. The SDK runs inside the isolate under the same [permission policy](/docs/permissions) as any guest code — snapshotting grants the SDK no extra capability. +- **Sidecar.** Owns the snapshot. It builds the snapshot once, caches it process-wide, and seeds each session's isolate from it. The SDK runs inside the isolate under the same [permission policy](/agentos/docs/permissions) as any guest code — snapshotting grants the SDK no extra capability. - **Executor.** The agent adapter restores into an isolate where the SDK is already on the global, reads it, and proceeds. It is untrusted guest code as always. ## The pipeline @@ -67,11 +67,11 @@ A startup snapshot can only capture a pure JS heap. The SDK's **module-initializ - Open an **fd, socket, timer, or worker**, or leave a **pending promise** at the end of evaluation. - Read **non-deterministic or per-session state** (`process.env`, cwd, model, `Date.now()`, `Math.random()`, a random UUID) into a module constant — it would be frozen to the build-time value. -Real-world SDKs frequently break these by accident. agentOS makes such an SDK snapshottable with **build-time transforms in the bundle** that defer the offending work to first use (e.g. wrap a module-level native singleton in a lazy proxy, inline a top-level config-file read, convert eager fire-and-forget imports to synchronous module references). Each transform asserts the source shape it expects, so an upstream SDK change surfaces as a build error rather than a silent regression. The full author-facing rules live in the [Software Definition](/docs/custom-software/definition) reference. +Real-world SDKs frequently break these by accident. agentOS makes such an SDK snapshottable with **build-time transforms in the bundle** that defer the offending work to first use (e.g. wrap a module-level native singleton in a lazy proxy, inline a top-level config-file read, convert eager fire-and-forget imports to synchronous module references). Each transform asserts the source shape it expects, so an upstream SDK change surfaces as a build error rather than a silent regression. The full author-facing rules live in the [Software Definition](/agentos/docs/custom-software/definition) reference. ## Opt-in, per agent -Snapshotting is **opt-in per agent**, via `agent.snapshot: true` on the [agent software descriptor](/docs/custom-software/definition), and requires the agent package to ship a snapshot-safe `dist/sdk-snapshot.js`. Today only the Pi agent opts in; other agents run the normal per-session import path. An agent qualifies by (1) being snapshot-safe and (2) building the bundle — there is nothing Pi-specific in the runtime mechanism. +Snapshotting is **opt-in per agent**, via `agent.snapshot: true` on the [agent software descriptor](/agentos/docs/custom-software/definition), and requires the agent package to ship a snapshot-safe `dist/sdk-snapshot.js`. Today only the Pi agent opts in; other agents run the normal per-session import path. An agent qualifies by (1) being snapshot-safe and (2) building the bundle — there is nothing Pi-specific in the runtime mechanism. **Current trade-off** diff --git a/website/src/content/docs/docs/architecture/agent-sessions.mdx b/docs/content/docs/architecture/agent-sessions.mdx similarity index 93% rename from website/src/content/docs/docs/architecture/agent-sessions.mdx rename to docs/content/docs/architecture/agent-sessions.mdx index 2b6681e8b6..4f90105258 100644 --- a/website/src/content/docs/docs/architecture/agent-sessions.mdx +++ b/docs/content/docs/architecture/agent-sessions.mdx @@ -48,6 +48,6 @@ An unexpected adapter exit evicts the live route and fails the active turn. Agen ## Next -- [Sessions](/docs/sessions) for the public API. -- [Sessions & Persistence](/docs/architecture/sessions-persistence) for SQLite and restoration. -- [Approvals](/docs/approvals) for ACP permission options. +- [Sessions](/agentos/docs/sessions) for the public API. +- [Sessions & Persistence](/agentos/docs/architecture/sessions-persistence) for SQLite and restoration. +- [Approvals](/agentos/docs/approvals) for ACP permission options. diff --git a/website/src/content/docs/docs/architecture/compiler-toolchain.mdx b/docs/content/docs/architecture/compiler-toolchain.mdx similarity index 86% rename from website/src/content/docs/docs/architecture/compiler-toolchain.mdx rename to docs/content/docs/architecture/compiler-toolchain.mdx index b302b8f38e..e25926c56a 100644 --- a/website/src/content/docs/docs/architecture/compiler-toolchain.mdx +++ b/docs/content/docs/architecture/compiler-toolchain.mdx @@ -6,16 +6,16 @@ skill: true 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. -The commands a guest runs through [process execution](/docs/processes), the shell +The commands a guest runs through [process execution](/agentos/docs/processes), the shell (`sh`) and the coreutils behind it, are not native host binaries. They are WebAssembly modules compiled ahead of time and mounted into the VM. This page covers how that command suite is produced: which toolchains compile it, what it links against, and how the resulting `.wasm` files become the guest's commands. For *why* WASM is a first-class guest and *how* it presents a POSIX surface at -runtime, see the [WASM VM](/docs/architecture/posix-syscalls) page. This page is the build-side +runtime, see the [WASM VM](/agentos/docs/architecture/posix-syscalls) page. This page is the build-side counterpart: it documents the toolchain that emits binaries carrying both -[the host-import layer and the WASI shim](/docs/architecture/posix-syscalls). +[the host-import layer and the WASI shim](/agentos/docs/architecture/posix-syscalls). ## Target: `wasm32-wasip1` @@ -62,7 +62,7 @@ process / user / network extensions. - **A patched `wasi-libc`.** The libc is the WASI standard library, modified so that the calls a normal command-line program performs resolve against the agentOS surface instead of failing or hitting unimplemented stubs. This is the - same patched libc the [Layer 2 shim](/docs/architecture/posix-syscalls) adapts at runtime; the + same patched libc the [Layer 2 shim](/agentos/docs/architecture/posix-syscalls) adapts at runtime; the build side and the runtime side are two ends of the same contract. - **The `wasi-ext` bindings.** These declare the extra WebAssembly import modules (`host_process`, `host_user`, `host_net`, and the small @@ -70,12 +70,12 @@ process / user / network extensions. into a binary is what lets its libc emit `fork` / `exec`, `getuid` / `getgid`, and `connect` / `listen` as ordinary-looking syscalls that the host runtime then services through the kernel. See - [Layer 1: custom host import modules](/docs/architecture/posix-syscalls) for the runtime half. + [Layer 1: custom host import modules](/agentos/docs/architecture/posix-syscalls) for the runtime half. The import declarations are compile-time only: linking `wasi-ext` tells the module *which* host imports to reference, but the calls are still routed through -the kernel and gated by the VM's [permission policy](/docs/permissions) at +the kernel and gated by the VM's [permission policy](/agentos/docs/permissions) at runtime. Building against `host_net` does not grant network access. @@ -85,14 +85,14 @@ The compiler toolchain's product is a set of `.wasm` files, one per command. Those files are what the runtime mounts as the guest's executables: when a guest invokes `ls`, `sh`, or any other bundled tool, the kernel resolves the name to the corresponding module, instantiates it with the host imports and the WASI -shim wired in, and runs it as a [child process](/docs/processes) with real +shim wired in, and runs it as a [child process](/agentos/docs/processes) with real process, user, and network semantics, all virtualized. The same path is open to your own programs. A program you compile for `wasm32-wasip1` runs as a guest command exactly like the bundled ones; link the `wasi-ext` bindings if it needs processes, users, or sockets, and leave them out for a pure-compute tool. Heavy native binaries that are not yet available as -WASM belong in an [external sandbox](/docs/sandboxes) instead. +WASM belong in an [external sandbox](/agentos/docs/sandboxes) instead. ## Recommendations @@ -103,4 +103,4 @@ WASM belong in an [external sandbox](/docs/sandboxes) instead. process / user / network host imports. - Keep the build and runtime contracts aligned: the patched `wasi-libc` and the `wasi-ext` import declarations a binary is compiled against are the same ones - the [WASM VM](/docs/architecture/posix-syscalls) runtime expects to satisfy. + the [WASM VM](/agentos/docs/architecture/posix-syscalls) runtime expects to satisfy. diff --git a/website/src/content/docs/docs/architecture/filesystem.mdx b/docs/content/docs/architecture/filesystem.mdx similarity index 91% rename from website/src/content/docs/docs/architecture/filesystem.mdx rename to docs/content/docs/architecture/filesystem.mdx index b7308e9556..c2747edc76 100644 --- a/website/src/content/docs/docs/architecture/filesystem.mdx +++ b/docs/content/docs/architecture/filesystem.mdx @@ -6,11 +6,11 @@ skill: true 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. -This page is an internals deep-dive on the **kernel virtual filesystem (VFS)**: how it is layered, how a guest `fs` syscall is routed through it, and how guest I/O is confined to the VM. For the user-facing API (reading, writing, mounting, persistence), see [Filesystem](/docs/filesystem). +This page is an internals deep-dive on the **kernel virtual filesystem (VFS)**: how it is layered, how a guest `fs` syscall is routed through it, and how guest I/O is confined to the VM. For the user-facing API (reading, writing, mounting, persistence), see [Filesystem](/agentos/docs/filesystem). The invariant this whole subsystem exists to uphold: **every guest filesystem operation is serviced by the kernel-owned VFS, never by a real host capability.** There is no host disk reachable from the guest. The VFS presents normal Linux semantics to tools while keeping every byte inside the kernel. -The security boundary is sidecar to executor. The VFS lives inside the trusted sidecar; the guest in the executor only ever *asks* for a filesystem operation. Confinement is the kernel's job, not the guest's. See the [Security Model](/docs/security-model) for the full threat model. +The security boundary is sidecar to executor. The VFS lives inside the trusted sidecar; the guest in the executor only ever *asks* for a filesystem operation. Confinement is the kernel's job, not the guest's. See the [Security Model](/agentos/docs/security-model) for the full threat model. ## Where the VFS sits @@ -50,13 +50,13 @@ 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](/docs/filesystem#mounts) for the user-facing config. +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. ## Routing a guest syscall When the guest calls, say, `readFileSync("/mnt/data/report.csv")`: -1. **Permission check.** The kernel verifies the filesystem scope is granted for that operation. Nothing is bound by default; access is denied until opted in (see [Permissions](/docs/permissions)). +1. **Permission check.** The kernel verifies the filesystem scope is granted for that operation. Nothing is bound by default; access is denied until opted in (see [Permissions](/agentos/docs/permissions)). 2. **Engine resolution.** The VFS walks the namespace and selects the engine owning the longest matching prefix (`/mnt/data` -> the S3 mount engine). 3. **Path normalization and confinement.** The remainder of the path is normalized within the owning engine's root. `.` and `..` segments are resolved *before* the operation reaches the backend, so the request cannot climb above the engine's root. 4. **Backend operation.** The owning engine's backend services the read/write/stat/etc. against its store (in-memory pages, the persisted base, a host directory, S3, ...). @@ -90,7 +90,7 @@ The result is that WASI filesystem access and the V8/Node `fs` path converge on ## Where to go next -- [Filesystem](/docs/filesystem): the user-facing API for reading, writing, mounting, and persistence. -- [Architecture](/docs/architecture): the components, trust boundary, and kernel-owned syscall paths. -- [Permissions](/docs/permissions): the filesystem scope the kernel checks on every operation. -- [Security Model](/docs/security-model): the full trust model and threat boundary. +- [Filesystem](/agentos/docs/filesystem): the user-facing API for reading, writing, mounting, and persistence. +- [Architecture](/agentos/docs/architecture): the components, trust boundary, and kernel-owned syscall paths. +- [Permissions](/agentos/docs/permissions): the filesystem scope the kernel checks on every operation. +- [Security Model](/agentos/docs/security-model): the full trust model and threat boundary. diff --git a/website/src/content/docs/docs/architecture/javascript-executor.mdx b/docs/content/docs/architecture/javascript-executor.mdx similarity index 96% rename from website/src/content/docs/docs/architecture/javascript-executor.mdx rename to docs/content/docs/architecture/javascript-executor.mdx index 7783578dd8..1db5d77092 100644 --- a/website/src/content/docs/docs/architecture/javascript-executor.mdx +++ b/docs/content/docs/architecture/javascript-executor.mdx @@ -11,8 +11,8 @@ channels carry data, and how Node stream backpressure reaches the actual transport. For socket ownership, loopback, DNS, and network policy, see -[Networking](/docs/architecture/networking). For the client-facing JavaScript -environment, see [JavaScript](/docs/javascript). +[Networking](/agentos/docs/architecture/networking). For the client-facing JavaScript +environment, see [JavaScript](/agentos/docs/javascript). Tokio never invokes guest JavaScript from a runtime worker. A Tokio task stores @@ -278,11 +278,11 @@ The main pieces are: ## See also -- [Networking](/docs/architecture/networking): kernel sockets, loopback, DNS, +- [Networking](/agentos/docs/architecture/networking): kernel sockets, loopback, DNS, and policy enforcement. -- [Processes](/docs/architecture/processes): how V8 executions fit into the +- [Processes](/agentos/docs/architecture/processes): how V8 executions fit into the virtual process model. -- [Limits & Observability](/docs/architecture/limits-and-observability): +- [Limits & Observability](/agentos/docs/architecture/limits-and-observability): resource classes, queue bounds, warnings, and typed overload failures. -- [Security Model](/docs/security-model): why the sidecar owns capabilities and +- [Security Model](/agentos/docs/security-model): why the sidecar owns capabilities and the executor is untrusted. diff --git a/website/src/content/docs/docs/architecture/limits-and-observability.mdx b/docs/content/docs/architecture/limits-and-observability.mdx similarity index 94% rename from website/src/content/docs/docs/architecture/limits-and-observability.mdx rename to docs/content/docs/architecture/limits-and-observability.mdx index 23ad942c21..911cf08a65 100644 --- a/website/src/content/docs/docs/architecture/limits-and-observability.mdx +++ b/docs/content/docs/architecture/limits-and-observability.mdx @@ -85,5 +85,5 @@ a parsed log line. ## See also -- [Resource Limits](/docs/resource-limits) — the full `limits` config surface. -- [Processes](/docs/architecture/processes) and [Sessions & Persistence](/docs/architecture/sessions-persistence) — the layers the queue chain runs through. +- [Resource Limits](/agentos/docs/resource-limits) — the full `limits` config surface. +- [Processes](/agentos/docs/architecture/processes) and [Sessions & Persistence](/agentos/docs/architecture/sessions-persistence) — the layers the queue chain runs through. diff --git a/website/src/content/docs/docs/architecture/networking.mdx b/docs/content/docs/architecture/networking.mdx similarity index 95% rename from website/src/content/docs/docs/architecture/networking.mdx rename to docs/content/docs/architecture/networking.mdx index 31147f497f..81ba12fc7b 100644 --- a/website/src/content/docs/docs/architecture/networking.mdx +++ b/docs/content/docs/architecture/networking.mdx @@ -6,7 +6,7 @@ skill: true 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. -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](/docs/networking). For the trust boundary this all sits inside, see [Architecture](/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`, 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). 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. @@ -131,7 +131,7 @@ Because previews ride the host fetch path, they are subject to loopback confinem ## Where to go next -- [Networking & Previews](/docs/networking): the `httpRequest` and preview URL API, with usage examples. -- [JavaScript Executor & Socket Reactor](/docs/architecture/javascript-executor): how Tokio readiness wakes V8, how the channel lanes are separated, and how Node stream backpressure reaches the transport. -- [Architecture](/docs/architecture): the client / sidecar / executor trust boundary this stack lives inside. -- [Security Model](/docs/security-model): the full in-scope and out-of-scope threat model. +- [Networking & Previews](/agentos/docs/networking): the `httpRequest` and preview URL 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. diff --git a/website/src/content/docs/docs/architecture/packages-and-command-resolution.mdx b/docs/content/docs/architecture/packages-and-command-resolution.mdx similarity index 92% rename from website/src/content/docs/docs/architecture/packages-and-command-resolution.mdx rename to docs/content/docs/architecture/packages-and-command-resolution.mdx index 1d4f3e1f85..ef6cabb74d 100644 --- a/website/src/content/docs/docs/architecture/packages-and-command-resolution.mdx +++ b/docs/content/docs/architecture/packages-and-command-resolution.mdx @@ -8,9 +8,9 @@ skill: true How a command name becomes a running program, and how the software that provides it is packaged and linked. Everything is real files under -[`/opt/agentos`](/docs/architecture/filesystem) — there is no command registry; the +[`/opt/agentos`](/agentos/docs/architecture/filesystem) — there is no command registry; the filesystem and `$PATH` are the only source of truth. For the host API that produces -packages, see [Software Definition](/docs/custom-software/definition). +packages, see [Software Definition](/agentos/docs/custom-software/definition). ## Overview @@ -57,8 +57,8 @@ packages, see [Software Definition](/docs/custom-software/definition). - **Resolve** — a real `$PATH` walk over the VFS; the first executable match wins. - **Dispatch** — by the file's *header* (`binfmt`): a `#!` shebang or a magic number. Never the name, never the extension. -- **Run** — on one of three runtimes: JavaScript (V8), WebAssembly, Python (Pyodide). See [Processes](/docs/architecture/processes). -- **Confine** — every process runs under the VM's single [permission policy](/docs/security-model). No per-command tiers. +- **Run** — on one of three runtimes: JavaScript (V8), WebAssembly, Python (Pyodide). See [Processes](/agentos/docs/architecture/processes). +- **Confine** — every process runs under the VM's single [permission policy](/agentos/docs/security-model). No per-command tiers. ## Packages @@ -106,7 +106,7 @@ A directory is a **valid package** when: multicall blob); `argv[0]` is the invoked name. - **It is self-contained** — every import/require/asset resolves inside the package; nothing comes from a host `node_modules`, pnpm store, or workspace at runtime - ([packaging](/docs/custom-software/definition) flattens/bundles deps in). + ([packaging](/agentos/docs/custom-software/definition) flattens/bundles deps in). - **Minimal metadata** — `package.json` carries only the command set (`bin`) and `version`; there is no command list beyond `bin`, no permission tiers (the [VM policy](#confinement--trust) governs every command), and no dependency list. A small **`agentos-package.json`** alongside it @@ -160,7 +160,7 @@ Linking is creating the `bin/` symlinks in a `$PATH` directory. agentOS follows ## Persistence Links and installed files are **filesystem entries**, so they persist exactly when their -[filesystem](/docs/architecture/filesystem) layer does — the same rule as VFS-persistent +[filesystem](/agentos/docs/architecture/filesystem) layer does — the same rule as VFS-persistent `pip`. A snapshotted/persistent volume keeps runtime installs and links across restart; an ephemeral one drops them on teardown. There is no package-specific persistence mechanism. @@ -194,7 +194,7 @@ Shebang handling matches `binfmt_script`: **Shell fallback.** On `ENOEXEC`, a POSIX shell re-runs a headerless script via `/bin/sh`. That -retry lives in the shell ([agentos-shell](/docs/architecture/processes)), not the dispatcher, +retry lives in the shell ([agentos-shell](/agentos/docs/architecture/processes)), not the dispatcher, which stays strictly `binfmt`-faithful. @@ -207,7 +207,7 @@ blob by its own path yields an `argv[0]` that selects no applet. ## Command resolution -A `$PATH` walk over the [VFS](/docs/architecture/filesystem), full Linux semantics: +A `$PATH` walk over the [VFS](/agentos/docs/architecture/filesystem), full Linux semantics: - A name **containing `/`** bypasses `$PATH` and resolves directly (relative to cwd, or absolute). - Otherwise each `:`-separated dir is searched in order; the first **executable** regular file @@ -232,9 +232,9 @@ agentos-software link ## Confinement & trust -Every process runs under the VM's single [permission policy](/docs/security-model) — like a +Every process runs under the VM's single [permission policy](/agentos/docs/security-model) — like a Linux process running with its user/namespace/container privileges, not privileges declared by -the binary. A package cannot grant itself permissions. The [trust boundary](/docs/security-model) +the binary. A package cannot grant itself permissions. The [trust boundary](/agentos/docs/security-model) is the sidecar (trusted) vs. the guest (untrusted): - **Linking changes discoverability, not privilege** — the policy is enforced at spawn, @@ -246,11 +246,11 @@ is the sidecar (trusted) vs. the guest (untrusted): `BASH_ENV`, `*PRELOAD` are stripped, as glibc does under `AT_SECURE`. - **Trusted vs. guest packages** — symlink-escape checks apply only to guest-writable runtime packages. - **Bounded** — the runtime link count is bounded; it warns on approach and fails with a typed - error naming the limit (see [Limits & Observability](/docs/architecture/limits-and-observability)). + error naming the limit (see [Limits & Observability](/agentos/docs/architecture/limits-and-observability)). ## See also -- [Software Definition](/docs/custom-software/definition) — the host API that produces these packages. -- [Processes](/docs/architecture/processes) — the JavaScript, WebAssembly, and Python runtimes. -- [Filesystem](/docs/architecture/filesystem) — the VFS, layers, and persistence. -- [Security Model](/docs/security-model) — the trust boundary and VM permission policy. +- [Software Definition](/agentos/docs/custom-software/definition) — the host API that produces these packages. +- [Processes](/agentos/docs/architecture/processes) — the JavaScript, WebAssembly, and Python runtimes. +- [Filesystem](/agentos/docs/architecture/filesystem) — the VFS, layers, and persistence. +- [Security Model](/agentos/docs/security-model) — the trust boundary and VM permission policy. diff --git a/website/src/content/docs/docs/architecture/posix-syscalls.mdx b/docs/content/docs/architecture/posix-syscalls.mdx similarity index 96% rename from website/src/content/docs/docs/architecture/posix-syscalls.mdx rename to docs/content/docs/architecture/posix-syscalls.mdx index aa7510fc58..4c8cf4ad64 100644 --- a/website/src/content/docs/docs/architecture/posix-syscalls.mdx +++ b/docs/content/docs/architecture/posix-syscalls.mdx @@ -7,7 +7,7 @@ skill: true 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. Not everything inside an agentOS VM is JavaScript. The shell (`sh`) and the -coreutils behind [process execution](/docs/processes) ship as WebAssembly +coreutils behind [process execution](/agentos/docs/processes) ship as WebAssembly binaries, and you can run your own WASM programs too. To make those programs behave like normal Linux tools, agentOS presents a POSIX syscall surface on top of WebAssembly. @@ -32,7 +32,7 @@ layers, and both route through the kernel rather than the host. Every WASM syscall, like every JS syscall, goes through the kernel-owned virtual filesystem, process table, and socket table. The extensions below add POSIX -*shape*; they do not add host access. See the [Security Model](/docs/security-model) +*shape*; they do not add host access. See the [Security Model](/agentos/docs/security-model) for the isolation boundary. @@ -89,9 +89,9 @@ declares extra WebAssembly import modules that the host runtime implements, so guest libc can call them as if they were ordinary syscalls. These bindings live in the `wasi-ext` crate and cover three areas: -- **`host_process`**: process management. Spawn a child process (argv, env, inherited stdio fds, working directory), wait for a child to exit, and related file-descriptor operations. This is what gives a WASM `sh` real [child process](/docs/processes) semantics; spawns go through the kernel process table. +- **`host_process`**: process management. Spawn a child process (argv, env, inherited stdio fds, working directory), wait for a child to exit, and related file-descriptor operations. This is what gives a WASM `sh` real [child process](/agentos/docs/processes) semantics; spawns go through the kernel process table. - **`host_user`**: user and group identity (uid, gid, user info). Base WASI has no concept of a user; this lets tools that call `getuid` / `getgid` see the VM's virtualized identity. -- **`host_net`**: TCP sockets (connect, listen, send, receive) through the kernel socket table, gated by the same [network permission policy](/docs/networking) as everything else. Base WASI has no general socket API. +- **`host_net`**: TCP sockets (connect, listen, send, receive) through the kernel socket table, gated by the same [network permission policy](/agentos/docs/networking) as everything else. Base WASI has no general socket API. A small `host_sleep_ms` binding provides blocking sleep. Together these let a guest compiled for `wasip1` behave as if it had a process model, user identity, diff --git a/website/src/content/docs/docs/architecture/processes.mdx b/docs/content/docs/architecture/processes.mdx similarity index 93% rename from website/src/content/docs/docs/architecture/processes.mdx rename to docs/content/docs/architecture/processes.mdx index 9c98235c1d..c443e1be09 100644 --- a/website/src/content/docs/docs/architecture/processes.mdx +++ b/docs/content/docs/architecture/processes.mdx @@ -9,8 +9,8 @@ skill: true 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 API (`process.exec`, `process.spawn`, `terminal.open`, lifecycle, the process tree), see -[Processes & Shell](/docs/processes). For the surrounding component and trust -model, see [Architecture](/docs/architecture). +[Processes & Shell](/agentos/docs/processes). For the surrounding component and trust +model, see [Architecture](/agentos/docs/architecture). Two invariants frame everything below: @@ -91,7 +91,7 @@ virtual PTY devices for this. The shell and the standard commands behind process execution are not special host helpers; they are ordinary guest processes that happen to be WebAssembly. -For the full WASM execution model see [WASM VM](/docs/architecture/posix-syscalls); here is how it +For the full WASM execution model see [WASM VM](/agentos/docs/architecture/posix-syscalls); here is how it maps onto the process table specifically. - **They are normal table entries.** Running `sh`, `ls`, `cat`, etc. allocates virtual PIDs and table entries exactly like any other process, with the WASM driver recorded on each. A pipeline of coreutils is several entries linked by kernel pipes. @@ -104,7 +104,7 @@ permission-checked spawn path, and uses the same kernel-owned stdio and PTYs. ## See also -- [Processes & Shell](/docs/processes): the client API for running and managing processes. -- [WASM VM](/docs/architecture/posix-syscalls): how WebAssembly guests get POSIX process, user, and network semantics. -- [Architecture](/docs/architecture): components, the trust boundary, and the request lifecycle. -- [Permissions](/docs/permissions): the policy the kernel checks on every spawn. +- [Processes & Shell](/agentos/docs/processes): the client API for running and managing processes. +- [WASM VM](/agentos/docs/architecture/posix-syscalls): how WebAssembly guests get POSIX process, user, and network semantics. +- [Architecture](/agentos/docs/architecture): components, the trust boundary, and the request lifecycle. +- [Permissions](/agentos/docs/permissions): the policy the kernel checks on every spawn. diff --git a/website/src/content/docs/docs/architecture/sessions-persistence.mdx b/docs/content/docs/architecture/sessions-persistence.mdx similarity index 100% rename from website/src/content/docs/docs/architecture/sessions-persistence.mdx rename to docs/content/docs/architecture/sessions-persistence.mdx diff --git a/website/src/content/docs/docs/architecture/tls-ssl.mdx b/docs/content/docs/architecture/tls-ssl.mdx similarity index 96% rename from website/src/content/docs/docs/architecture/tls-ssl.mdx rename to docs/content/docs/architecture/tls-ssl.mdx index c1ef2f6dc0..c374b4c71d 100644 --- a/website/src/content/docs/docs/architecture/tls-ssl.mdx +++ b/docs/content/docs/architecture/tls-ssl.mdx @@ -4,7 +4,7 @@ description: "How agentOS uses in-guest mbedTLS plus a VM CA bundle for curl / w skill: true --- -This is the internals view of how TLS works for guest CLI tools (`curl`, `wget`, `git`, `ssh`) that run as `wasm32-wasip1` in the untrusted executor. For how bytes actually move between endpoints, see [Networking](/docs/architecture/networking); for how the tools are compiled, see [Compiler Toolchain](/docs/architecture/compiler-toolchain); for the trust boundary this sits inside, see [Security Model](/docs/security-model). +This is the internals view of how TLS works for guest CLI tools (`curl`, `wget`, `git`, `ssh`) that run as `wasm32-wasip1` in the untrusted executor. For how bytes actually move between endpoints, see [Networking](/agentos/docs/architecture/networking); for how the tools are compiled, see [Compiler Toolchain](/agentos/docs/architecture/compiler-toolchain); for the trust boundary this sits inside, see [Security Model](/agentos/docs/security-model). The governing rule: **verification happens in-guest, against a CA bundle shipped inside the VM.** The sidecar is a dumb ciphertext pipe — the untrusted guest never asks the trusted host to authenticate a server on its behalf. diff --git a/website/src/content/docs/docs/authentication.mdx b/docs/content/docs/authentication.mdx similarity index 85% rename from website/src/content/docs/docs/authentication.mdx rename to docs/content/docs/authentication.mdx index 519ebe36c2..c44ead5728 100644 --- a/website/src/content/docs/docs/authentication.mdx +++ b/docs/content/docs/authentication.mdx @@ -4,7 +4,7 @@ description: "Authenticate connections to agentOS actors using Rivet Actor conne skill: true --- -agentOS uses the same authentication system as [Rivet Actors](/docs/actors/authentication): clients send credentials as connection params, and you validate them server-side. +agentOS uses the same authentication system as [Rivet Actors](/actors/docs/authentication): clients send credentials as connection params, and you validate them server-side. - Clients pass credentials in `params` when they connect. - Validate them on the server in `onBeforeConnect` (throw to reject the connection), or extract user data into connection state with `createConnState` (read it in actions via `c.conn.state`). @@ -21,4 +21,4 @@ The server declares the credential shape and validates it in `onBeforeConnect` ( -See [Actor Authentication](/docs/actors/authentication) for JWT validation, role-based access control, external auth providers, and token caching. +See [Actor Authentication](/actors/docs/authentication) for JWT validation, role-based access control, external auth providers, and token caching. diff --git a/website/src/content/docs/docs/bash.mdx b/docs/content/docs/bash.mdx similarity index 73% rename from website/src/content/docs/docs/bash.mdx rename to docs/content/docs/bash.mdx index 46921b10ed..844991b93e 100644 --- a/website/src/content/docs/docs/bash.mdx +++ b/docs/content/docs/bash.mdx @@ -12,8 +12,8 @@ Python, and package workflows. - **`process.execFile()`**: Injection-safe; args are never parsed by a shell. - **In-VM only**: Commands run inside the VM, never in the host shell. -For multi-step work, consider letting the agent write [JavaScript](/docs/javascript) -or [Python](/docs/python) instead — one round trip and real data structures +For multi-step work, consider letting the agent write [JavaScript](/agentos/docs/javascript) +or [Python](/agentos/docs/python) instead — one round trip and real data structures rather than a chain of shell calls. ## Run commands @@ -29,22 +29,22 @@ stdin, a PTY, output replay, signals, and waiting. ## Files and software -Shell commands see the persistent [filesystem](/docs/filesystem) shared by +Shell commands see the persistent [filesystem](/agentos/docs/filesystem) shared by agents, JavaScript, and Python. Common POSIX commands ship by default; more is -projected through the [software registry](/docs/software). +projected through the [software registry](/agentos/docs/software). ## Bindings -[Bindings](/docs/bindings) appear as commands, so pipelines use trusted host +[Bindings](/agentos/docs/bindings) appear as commands, so pipelines use trusted host capabilities without putting credentials inside the VM. ## Permissions, limits, and timeouts -Every command inherits the VM [permission policy](/docs/permissions) and -[resource limits](/docs/resource-limits). +Every command inherits the VM [permission policy](/agentos/docs/permissions) and +[resource limits](/agentos/docs/resource-limits). diff --git a/website/src/content/docs/docs/bindings.mdx b/docs/content/docs/bindings.mdx similarity index 91% rename from website/src/content/docs/docs/bindings.mdx rename to docs/content/docs/bindings.mdx index a69b18bc47..bb18fdc341 100644 --- a/website/src/content/docs/docs/bindings.mdx +++ b/docs/content/docs/bindings.mdx @@ -4,7 +4,7 @@ description: "Expose custom host functions to agents as CLI commands inside the skill: true --- -Expose your host JavaScript functions (defined with Zod input schemas) to agents as auto-generated CLI commands installed at `/usr/local/bin/agentos-{name}` inside the VM, injected into the agent's [system prompt](/docs/system-prompt) and callable inside scripts for code-mode token savings. +Expose your host JavaScript functions (defined with Zod input schemas) to agents as auto-generated CLI commands installed at `/usr/local/bin/agentos-{name}` inside the VM, injected into the agent's [system prompt](/agentos/docs/system-prompt) and callable inside scripts for code-mode token savings. ## Getting started @@ -34,7 +34,7 @@ Optional fields (via `.optional()`) become optional flags. Required fields are e ### What the agent sees -When bindings are registered, CLI shims are installed at `/usr/local/bin/agentos-{name}` inside the VM and the binding list is injected into the agent's [system prompt](/docs/system-prompt), so keep binding descriptions concise to save tokens. +When bindings are registered, CLI shims are installed at `/usr/local/bin/agentos-{name}` inside the VM and the binding list is injected into the agent's [system prompt](/agentos/docs/system-prompt), so keep binding descriptions concise to save tokens. The agent interacts with bindings as shell commands: @@ -82,7 +82,7 @@ AgentOS supports two ways to give agents access to external functionality: **bin | **Latency** | Near-zero. Bound directly to the host process. | Extra network hop to reach the MCP server | | **Setup** | Define bindings in your actor code with Zod schemas | Configure any standard MCP server | -Use bindings when you want to expose your own JavaScript functions to agents. Use MCP servers when you want to connect to existing third-party services. See [Sessions](/docs/sessions#open-a-session) for MCP server configuration. +Use bindings when you want to expose your own JavaScript functions to agents. Use MCP servers when you want to connect to existing third-party services. See [Sessions](/agentos/docs/sessions#open-a-session) for MCP server configuration. ## Security diff --git a/website/src/content/docs/docs/browser.mdx b/docs/content/docs/browser.mdx similarity index 96% rename from website/src/content/docs/docs/browser.mdx rename to docs/content/docs/browser.mdx index 7e8d1dc81f..f4509c83cc 100644 --- a/website/src/content/docs/docs/browser.mdx +++ b/docs/content/docs/browser.mdx @@ -65,5 +65,5 @@ browse cloud projects list # list Browserbase projects ``` -The [interactive driver mode](https://docs.browserbase.com/integrations/skills/browse-cli) (`browse open`, `browse click`, …) is not supported inside the VM yet ([#1631](https://github.com/rivet-dev/agentos/issues/1631)). For interactive automation, run `browse` inside an external sandbox via [External Sandboxes](/docs/sandboxes). +The [interactive driver mode](https://docs.browserbase.com/integrations/skills/browse-cli) (`browse open`, `browse click`, …) is not supported inside the VM yet ([#1631](https://github.com/rivet-dev/agentos/issues/1631)). For interactive automation, run `browse` inside an external sandbox via [External Sandboxes](/agentos/docs/sandboxes). diff --git a/website/src/content/docs/docs/core.mdx b/docs/content/docs/core.mdx similarity index 92% rename from website/src/content/docs/docs/core.mdx rename to docs/content/docs/core.mdx index f02de4ade5..ad2d1d3af1 100644 --- a/website/src/content/docs/docs/core.mdx +++ b/docs/content/docs/core.mdx @@ -19,8 +19,8 @@ actor API. | Preview URLs | None | Built-in signed URL server | | Multiplayer | N/A | Multiple clients per actor | | Orchestration | N/A | Workflows, queues, cron | -| Agent-to-agent | Custom | Built into [Rivet Actors](/docs/agent-to-agent) | -| Authentication | Set up yourself | [Docs](/docs/authentication) | +| Agent-to-agent | Custom | Built into [Rivet Actors](/agentos/docs/agent-to-agent) | +| Authentication | Set up yourself | [Docs](/agentos/docs/authentication) | - Use [Rivet Actors](https://rivet.dev/docs/actors) for persistence, networking, and orchestration. @@ -53,7 +53,7 @@ directly — no actor runtime, no client/server split. - All VMs default to a single process-global sidecar (the `default` pool); each extra VM adds only a V8 isolate + its kernel state. - This keeps per-VM memory in the tens of MB and warm creation in single-digit - ms (see [Performance](/docs/performance)). + ms (see [Performance](/agentos/docs/performance)). - Automatic for `agentOS()`, `AgentOs.create()`, and Rivet Actors. - Disposing a VM tears down only that VM; the sidecar is reused for the host process lifetime. @@ -124,12 +124,12 @@ bounded, serializable response DTO. ## Configuration reference - All VM config is a single flat object passed to `AgentOs.create()`. -- The [`agentOS()` actor](/docs/quickstart) accepts the same options and layers +- The [`agentOS()` actor](/agentos/docs/quickstart) accepts the same options and layers persistence, sleep/wake, and preview URLs on top. -See [Mounts](#mounts) and [Software](/docs/software). +See [Mounts](#mounts) and [Software](/agentos/docs/software). ### Session events @@ -144,7 +144,7 @@ See [Mounts](#mounts) and [Software](/docs/software). ### Timeouts and sleep -- Action timeouts and automatic sleep/wake are [`agentOS()` actor](/docs/quickstart) +- Action timeouts and automatic sleep/wake are [`agentOS()` actor](/agentos/docs/quickstart) features, not the direct VM API. - A direct VM stays alive until `dispose()`. See - [Persistence & Sleep](/docs/persistence). + [Persistence & Sleep](/agentos/docs/persistence). diff --git a/website/src/content/docs/docs/crash-course.mdx b/docs/content/docs/crash-course.mdx similarity index 86% rename from website/src/content/docs/docs/crash-course.mdx rename to docs/content/docs/crash-course.mdx index 8c710881df..634504f76e 100644 --- a/website/src/content/docs/docs/crash-course.mdx +++ b/docs/content/docs/crash-course.mdx @@ -40,7 +40,7 @@ Create agent sessions, send prompts, and stream responses in realtime. Transcrip -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/sessions)* +*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/agentos/docs/sessions)* ### Approvals @@ -52,7 +52,7 @@ Approve or deny agent tool use with human-in-the-loop patterns or auto-approve f -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/approvals)* +*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/agentos/docs/approvals)* ### Bindings @@ -64,11 +64,11 @@ Expose your JavaScript functions to agents as CLI commands inside the VM. Each b -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/bindings) or [Documentation](/docs/bindings)* +*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/bindings) or [Documentation](/agentos/docs/bindings)* ### Agent-to-Agent -Let one agent call another through a [binding](/docs/bindings). The coder gets a `review` binding it invokes itself, which bridges into the reviewer's isolated VM. +Let one agent call another through a [binding](/agentos/docs/bindings). The coder gets a `review` binding it invokes itself, which bridges into the reviewer's isolated VM. @@ -76,7 +76,7 @@ Let one agent call another through a [binding](/docs/bindings). The coder gets a -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/agent-to-agent)* +*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/agentos/docs/agent-to-agent)* ### Multiplayer @@ -88,7 +88,7 @@ Connect multiple clients to the same agent VM. All subscribers see session outpu -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/multiplayer)* +*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/agentos/docs/multiplayer)* ### Workflows & Graphs @@ -96,7 +96,7 @@ Orchestrate multi-step agent tasks with durable workflows that survive crashes a -[Documentation](/docs/workflows) +[Documentation](/agentos/docs/workflows) ## Operating System @@ -110,7 +110,7 @@ Read, write, and manage files inside the VM. The `/home/agentos` directory is pe -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/filesystem)* +*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/agentos/docs/filesystem)* ### Processes & Shell @@ -122,7 +122,7 @@ Execute commands, spawn long-running processes, and open interactive shells. -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/processes)* +*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/agentos/docs/processes)* ### Networking & Previews @@ -134,7 +134,7 @@ Proxy HTTP requests into VMs with `httpRequest`. Create actor-namespaced preview -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/networking)* +*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/agentos/docs/networking)* ### Crons & Loops @@ -146,7 +146,7 @@ Schedule recurring commands and agent sessions with cron expressions. -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/cron)* +*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/agentos/docs/cron)* ### External Sandboxes @@ -154,6 +154,6 @@ agentOS uses a hybrid model: agents run in a lightweight VM by default and mount -[Documentation](/docs/sandboxes) +[Documentation](/agentos/docs/sandboxes) {/* SKILL_OVERVIEW_END */} diff --git a/website/src/content/docs/docs/cron.mdx b/docs/content/docs/cron.mdx similarity index 100% rename from website/src/content/docs/docs/cron.mdx rename to docs/content/docs/cron.mdx diff --git a/website/src/content/docs/docs/custom-software/building-wasm.mdx b/docs/content/docs/custom-software/building-wasm.mdx similarity index 91% rename from website/src/content/docs/docs/custom-software/building-wasm.mdx rename to docs/content/docs/custom-software/building-wasm.mdx index 2ab44f4f4c..eb8738ccdd 100644 --- a/website/src/content/docs/docs/custom-software/building-wasm.mdx +++ b/docs/content/docs/custom-software/building-wasm.mdx @@ -61,4 +61,4 @@ Install a published package and pass it to `software`. Registry WASM packages ar -Meta-packages bundle a full set, e.g. `@agentos-software/common` (coreutils, sed, grep, gawk, findutils, diffutils, tar, gzip). Run the commands from the client; see [Processes & Shell](/docs/processes). Browse the full catalog on the [Registry](/registry), and see the package descriptor in [Software Definition](/docs/custom-software/definition). To ship your package to npm or use a local build, see [Publishing Packages](/docs/custom-software/publishing). +Meta-packages bundle a full set, e.g. `@agentos-software/common` (coreutils, sed, grep, gawk, findutils, diffutils, tar, gzip). Run the commands from the client; see [Processes & Shell](/agentos/docs/processes). Browse the full catalog on the [Registry](/registry), and see the package descriptor in [Software Definition](/agentos/docs/custom-software/definition). To ship your package to npm or use a local build, see [Publishing Packages](/agentos/docs/custom-software/publishing). diff --git a/website/src/content/docs/docs/custom-software/definition.mdx b/docs/content/docs/custom-software/definition.mdx similarity index 93% rename from website/src/content/docs/docs/custom-software/definition.mdx rename to docs/content/docs/custom-software/definition.mdx index be0ba98720..0742e83d47 100644 --- a/website/src/content/docs/docs/custom-software/definition.mdx +++ b/docs/content/docs/custom-software/definition.mdx @@ -15,7 +15,7 @@ A package is **self-contained**: package it first, then point `defineSoftware()` 1. **You have** C or Rust source for a command. (Most common commands already ship as `@agentos-software/*` packages you can use directly — compile only new or custom ones.) -2. **Compile it** to WebAssembly — see [Building Binaries](/docs/custom-software/building-wasm). There's **no `pack` step**: WASM binaries are self-contained, so the compile output is already the package — a `bin/` of `\0asm` files plus a `package.json` for the name/version: +2. **Compile it** to WebAssembly — see [Building Binaries](/agentos/docs/custom-software/building-wasm). There's **no `pack` step**: WASM binaries are self-contained, so the compile output is already the package — a `bin/` of `\0asm` files plus a `package.json` for the name/version: ``` my-cmds/ @@ -182,7 +182,7 @@ Defer all of the above behind functions or lazy `import()` that run per session. ## Next steps -- [Custom Agents](/docs/agents/custom): the agent-focused guide. -- [Building Binaries](/docs/custom-software/building-wasm): compile WASM commands and use the registry. -- [Packages & command resolution](/docs/architecture/packages-and-command-resolution): how packages mount and resolve. +- [Custom Agents](/agentos/docs/agents/custom): the agent-focused guide. +- [Building Binaries](/agentos/docs/custom-software/building-wasm): compile WASM commands and use the registry. +- [Packages & command resolution](/agentos/docs/architecture/packages-and-command-resolution): how packages mount and resolve. - [Request Software](https://github.com/rivet-dev/agentos/issues/new/choose): ask for a package you need. diff --git a/website/src/content/docs/docs/custom-software/publishing.mdx b/docs/content/docs/custom-software/publishing.mdx similarity index 95% rename from website/src/content/docs/docs/custom-software/publishing.mdx rename to docs/content/docs/custom-software/publishing.mdx index 297eb8f69d..83f3a7bf04 100644 --- a/website/src/content/docs/docs/custom-software/publishing.mdx +++ b/docs/content/docs/custom-software/publishing.mdx @@ -18,7 +18,7 @@ Every package is an npm package whose default export points at a self-contained ## Building -In the AgentOS registry, the `just` recipes drive the toolchain (see [Building Binaries](/docs/custom-software/building-wasm)): +In the AgentOS registry, the `just` recipes drive the toolchain (see [Building Binaries](/agentos/docs/custom-software/building-wasm)): ```bash just toolchain-build # compile the native wasm binaries (once per checkout) @@ -77,4 +77,4 @@ For a JS agent, `pack` replaces `stage`/`build`: npx @rivet-dev/agentos-toolchain pack . --out dist/package --agent my-acp-entrypoint ``` -The published package is a plain npm dependency — consumers import its descriptor and pass it to `software` exactly like the software packages. See [Software Definition](/docs/custom-software/definition) for the descriptor shape. +The published package is a plain npm dependency — consumers import its descriptor and pass it to `software` exactly like the software packages. See [Software Definition](/agentos/docs/custom-software/definition) for the descriptor shape. diff --git a/website/src/content/docs/docs/debugging.mdx b/docs/content/docs/debugging.mdx similarity index 90% rename from website/src/content/docs/docs/debugging.mdx rename to docs/content/docs/debugging.mdx index 84be7caff8..8179120a19 100644 --- a/website/src/content/docs/docs/debugging.mdx +++ b/docs/content/docs/debugging.mdx @@ -3,7 +3,7 @@ title: "Debugging" description: "Capture agent logs and runtime (sidecar) logs to diagnose sessions, tool calls, and crashes." --- -Before reaching for logs, open the [inspector](/docs/inspector): it shows the live transcript, pending permission requests (the most common reason an agent looks stuck), and the process tree. +Before reaching for logs, open the [inspector](/agentos/docs/inspector): it shows the live transcript, pending permission requests (the most common reason an agent looks stuck), and the process tree. Two log streams help diagnose what's happening inside a VM: the **agent's** own output and the **runtime (sidecar)** logs. @@ -13,7 +13,7 @@ The coding agent (ACP adapter) runs as a process inside the VM and uses **stdout -It's a VM-level option covering every session's agent process; if omitted, chunks are written to the host `process.stderr` by default. See [Sessions → Agent logs](/docs/sessions#agent-logs). +It's a VM-level option covering every session's agent process; if omitted, chunks are written to the host `process.stderr` by default. See [Sessions → Agent logs](/agentos/docs/sessions#agent-logs). ## Agent crashes (`onAgentExit`) @@ -30,7 +30,7 @@ const agentOs = await AgentOs.create({ }); ``` -The durable session and committed SQLite history remain available. The crash *reason* is on the adapter's stderr; the exit event reports that the live runtime disappeared. A later explicit prompt performs restoration. See [Sessions](/docs/sessions). +The durable session and committed SQLite history remain available. The crash *reason* is on the adapter's stderr; the exit event reports that the live runtime disappeared. A later explicit prompt performs restoration. See [Sessions](/agentos/docs/sessions). ## Runtime logs (sidecar) diff --git a/website/src/content/docs/docs/filesystem.mdx b/docs/content/docs/filesystem.mdx similarity index 89% rename from website/src/content/docs/docs/filesystem.mdx rename to docs/content/docs/filesystem.mdx index 16219c2e50..00580e23ba 100644 --- a/website/src/content/docs/docs/filesystem.mdx +++ b/docs/content/docs/filesystem.mdx @@ -4,7 +4,7 @@ description: "Read, write, mount, and manage files inside agentOS, all backed by skill: true --- -Each VM has its own filesystem that the agent works in. Guest `fs` calls never touch the host disk, and it persists automatically across sleep/wake with no setup. See [Persistence](/docs/persistence) for the details. +Each VM has its own filesystem that the agent works in. Guest `fs` calls never touch the host disk, and it persists automatically across sleep/wake with no setup. See [Persistence](/agentos/docs/persistence) for the details. ## Mounts @@ -62,7 +62,7 @@ The actor's durable root is handled separately: the sidecar connects directly to ## File operations -These operations are primarily what the agent uses inside the VM, and are also available from the client to seed inputs and read results. For large or read-only inputs (a repo, a dataset), a read-only [host mount](#mounts) is faster than copying files in. Programs that need stdin or live output use exec instead (see the [Direct VM API](/docs/core)). +These operations are primarily what the agent uses inside the VM, and are also available from the client to seed inputs and read results. For large or read-only inputs (a repo, a dataset), a read-only [host mount](#mounts) is faster than copying files in. Programs that need stdin or live output use exec instead (see the [Direct VM API](/agentos/docs/core)). ### Read and write @@ -99,18 +99,18 @@ const vm = agentOS({ }); ``` -See [Permissions](/docs/permissions) for the full configuration. +See [Permissions](/agentos/docs/permissions) for the full configuration. ## Sandboxes -For heavier workloads, run a full Linux [external sandbox](/docs/sandboxes) alongside the VM and mount its filesystem into agentOS. The agent then reads and writes the sandbox's files through the same `fs` APIs while the sandbox handles execution. +For heavier workloads, run a full Linux [external sandbox](/agentos/docs/sandboxes) alongside the VM and mount its filesystem into agentOS. The agent then reads and writes the sandbox's files through the same `fs` APIs while the sandbox handles execution. ## Default layout With no `mounts` configured, every VM boots an Alpine-based root filesystem with the standard POSIX directories: - `/home/agentos`: the agent's home directory (`$HOME`) and default working directory (`pwd`) when spawned, where it reads and writes (mounts land under it, e.g. `/home/agentos/data`). -- `/bin`, `/sbin`, `/usr`: installed commands (common POSIX utilities by default, plus any [software](/docs/software) you add). +- `/bin`, `/sbin`, `/usr`: installed commands (common POSIX utilities by default, plus any [software](/agentos/docs/software) you add). - `/etc`, `/lib`, `/opt`, `/root`, `/run`, `/srv`, `/tmp`, `/var`, `/mnt`: standard system paths. It is backed by the VM's own filesystem and persisted across sleep/wake. Nothing comes from or touches the host disk. diff --git a/website/src/content/docs/docs/index.mdx b/docs/content/docs/index.mdx similarity index 74% rename from website/src/content/docs/docs/index.mdx rename to docs/content/docs/index.mdx index 6d9947ed53..e12b48adba 100644 --- a/website/src/content/docs/docs/index.mdx +++ b/docs/content/docs/index.mdx @@ -8,13 +8,13 @@ network control — a lightweight VM in your own process with bindings, permissi and orchestration built in. - + Boot a VM and run your first coding agent. - + Learn the core agentOS concepts. - + Run Pi, Claude Code, Codex, and OpenCode. diff --git a/website/src/content/docs/docs/inspector.mdx b/docs/content/docs/inspector.mdx similarity index 87% rename from website/src/content/docs/docs/inspector.mdx rename to docs/content/docs/inspector.mdx index 49d14a797c..3e94bb45cc 100644 --- a/website/src/content/docs/docs/inspector.mdx +++ b/docs/content/docs/inspector.mdx @@ -24,30 +24,30 @@ The stock rivetkit tabs (state, connections, console) are replaced by the agentO A chat view of every session on the VM: user and agent messages, thinking, tool calls with their inputs and outputs, and the agent's plan. Plumbing events collapse into expandable rows so they never dominate the pane. -The composer at the bottom drives the agent directly: pick an agent type, set per-session env vars (such as an API key, which stays in your browser), and send prompts. This is the same data and the same actions your code uses via `openSession`, `prompt`, and the `sessionEvent` stream. See [Sessions](/docs/sessions). +The composer at the bottom drives the agent directly: pick an agent type, set per-session env vars (such as an API key, which stays in your browser), and send prompts. This is the same data and the same actions your code uses via `openSession`, `prompt`, and the `sessionEvent` stream. See [Sessions](/agentos/docs/sessions). ## Approvals -When an agent asks for permission, a banner appears above every tab with the request and its reply options. The agent's turn blocks until someone answers, so an unanswered request is the most common reason an agent looks stuck. See [Approvals](/docs/approvals). +When an agent asks for permission, a banner appears above every tab with the request and its reply options. The agent's turn blocks until someone answers, so an unanswered request is the most common reason an agent looks stuck. See [Approvals](/agentos/docs/approvals). ## Filesystem -Browse the VM's filesystem and read files, the same view your code gets through the fs API. Note that the root filesystem is in-memory; files outside persisted mounts do not survive VM restarts. See [Filesystem](/docs/filesystem). +Browse the VM's filesystem and read files, the same view your code gets through the fs API. Note that the root filesystem is in-memory; files outside persisted mounts do not survive VM restarts. See [Filesystem](/agentos/docs/filesystem). ## System Everything about the machine itself, in one scroll view. When the VM is asleep, the tab says so instead of waking it. -- **Processes** — the full kernel process tree, refreshed live. Select a process for its details (ppid, cwd, driver, exit code), stop or kill it, and watch a live output tail for processes spawned through the SDK. See [Processes & Shell](/docs/processes). -- **Software** — installed software bundles with their commands. See [Software](/docs/software). -- **Mounts** — the configured mounts with their access modes. See [Sandbox Mounting](/docs/sandbox). -- **Preview links** — create a signed URL to an HTTP server on a port inside the VM. See [Networking](/docs/networking). +- **Processes** — the full kernel process tree, refreshed live. Select a process for its details (ppid, cwd, driver, exit code), stop or kill it, and watch a live output tail for processes spawned through the SDK. See [Processes & Shell](/agentos/docs/processes). +- **Software** — installed software bundles with their commands. See [Software](/agentos/docs/software). +- **Mounts** — the configured mounts with their access modes. See [Sandbox Mounting](/agentos/docs/sandboxes). +- **Preview links** — create a signed URL to an HTTP server on a port inside the VM. See [Networking](/agentos/docs/networking). Actor identity and lifecycle controls (id, key, runner, sleep, destroy) live in the dashboard's own Metadata tab; the System tab covers only what is inside the VM. ## VM status badges -When something needs attention, compact badges appear in each tab's own toolbar: a state note when the VM is asleep, shut down after an error, or the sidecar is unhealthy, and an amber warnings pill (resource-limit warnings and agent crash exits, expandable into a panel). While the VM is simply healthy nothing shows; the live session count sits in the Transcript tab's session list. The health poll behind the badges never wakes a sleeping VM, so leaving the inspector open never boots anything. The warnings are the same data your code receives through `onLimitWarning` and `onAgentExit`; see [Resource Limits](/docs/resource-limits) and [Debugging](/docs/debugging). +When something needs attention, compact badges appear in each tab's own toolbar: a state note when the VM is asleep, shut down after an error, or the sidecar is unhealthy, and an amber warnings pill (resource-limit warnings and agent crash exits, expandable into a panel). While the VM is simply healthy nothing shows; the live session count sits in the Transcript tab's session list. The health poll behind the badges never wakes a sleeping VM, so leaving the inspector open never boots anything. The warnings are the same data your code receives through `onLimitWarning` and `onAgentExit`; see [Resource Limits](/agentos/docs/resource-limits) and [Debugging](/agentos/docs/debugging). ## Access control diff --git a/website/src/content/docs/docs/javascript-compatibility.mdx b/docs/content/docs/javascript-compatibility.mdx similarity index 93% rename from website/src/content/docs/docs/javascript-compatibility.mdx rename to docs/content/docs/javascript-compatibility.mdx index 363dc36097..08d95c51fd 100644 --- a/website/src/content/docs/docs/javascript-compatibility.mdx +++ b/docs/content/docs/javascript-compatibility.mdx @@ -38,7 +38,7 @@ or implemented in the isolate is denied. | `timers`, `timers/promises` | Timeout, interval, immediate, promise variants. | | `stream/web`, `stream/consumers`, `stream/promises` | Web Streams + stream helpers. | -- Network builtins obey the VM [permission policy](/docs/permissions). +- Network builtins obey the VM [permission policy](/agentos/docs/permissions). - Network access is **denied until granted** by the VM creator. ## In-isolate builtins @@ -66,9 +66,9 @@ or implemented in the isolate is denied. - ESM and CommonJS both use the VM filesystem and normal `node_modules` resolution. - Console/stream output flows through the bounded process-output path — see - [Processes & Shells](/docs/processes). + [Processes & Shells](/agentos/docs/processes). -Back to the [JavaScript guide](/docs/javascript) for TypeScript, packages, +Back to the [JavaScript guide](/agentos/docs/javascript) for TypeScript, packages, files, processes, networking, bindings, permissions, and limits. diff --git a/website/src/content/docs/docs/javascript.mdx b/docs/content/docs/javascript.mdx similarity index 89% rename from website/src/content/docs/docs/javascript.mdx rename to docs/content/docs/javascript.mdx index bbf02f163d..4f772b8921 100644 --- a/website/src/content/docs/docs/javascript.mdx +++ b/docs/content/docs/javascript.mdx @@ -9,7 +9,7 @@ real Node.js surface: `node:fs`, `node:child_process`, sockets, and npm. Letting an agent write code instead of chaining one tool call per step is called [Code Mode](https://blog.cloudflare.com/code-mode/). It has a few advantages over -driving [Bash](/docs/bash): +driving [Bash](/agentos/docs/bash): - **Fewer tokens**: Ten chained operations cost one round trip, not ten. - **Type checking**: Validate generated TypeScript before you run it. @@ -88,19 +88,19 @@ other executions. -See [Filesystem](/docs/filesystem), [Processes & Shells](/docs/processes), and -[Networking & Previews](/docs/networking). +See [Filesystem](/agentos/docs/filesystem), [Processes & Shells](/agentos/docs/processes), and +[Networking & Previews](/agentos/docs/networking). ## Bindings -Guest code invokes [bindings](/docs/bindings) as ordinary typed commands, so host +Guest code invokes [bindings](/agentos/docs/bindings) as ordinary typed commands, so host credentials stay outside the VM. ## Permissions, limits, and timeouts -Every operation inherits the VM [permission policy](/docs/permissions) and -[resource limits](/docs/resource-limits). +Every operation inherits the VM [permission policy](/agentos/docs/permissions) and +[resource limits](/agentos/docs/resource-limits). diff --git a/website/src/content/docs/docs/limitations.mdx b/docs/content/docs/limitations.mdx similarity index 75% rename from website/src/content/docs/docs/limitations.mdx rename to docs/content/docs/limitations.mdx index 4289532386..9c6e8c0e2c 100644 --- a/website/src/content/docs/docs/limitations.mdx +++ b/docs/content/docs/limitations.mdx @@ -8,17 +8,17 @@ agentOS is a Linux environment with a POSIX-compliant virtual kernel. It handles ## Sandbox mounting -When a workload needs a full Linux OS, agents can escalate to a full sandbox on demand without changing code. The [external sandbox](/docs/sandboxes) extension mounts the sandbox as a filesystem and lets you execute commands on it, like mounting a hard drive on your own machine. Files written in the VM are available in the sandbox and vice versa. +When a workload needs a full Linux OS, agents can escalate to a full sandbox on demand without changing code. The [external sandbox](/agentos/docs/sandboxes) extension mounts the sandbox as a filesystem and lets you execute commands on it, like mounting a hard drive on your own machine. Files written in the VM are available in the sandbox and vice versa. -See [agentOS vs Sandbox](/docs/versus-sandbox) for a detailed comparison. +See [agentOS vs Sandbox](/agentos/docs/versus-sandbox) for a detailed comparison. ## Limitations ### Software registry -agentOS uses its own [software registry](/registry) of popular tools cross-compiled for the runtime. You cannot download and install arbitrary binaries (for example via `curl` or `apt`), and standard Linux package managers (`apt`, `yum`) are not available since agentOS runs a streamlined Linux environment rather than a full distribution. Native binaries that are not yet available in the registry (such as Go, Rust, or C++ toolchains) require a full [external sandbox](/docs/sandboxes). +agentOS uses its own [software registry](/registry) of popular tools cross-compiled for the runtime. You cannot download and install arbitrary binaries (for example via `curl` or `apt`), and standard Linux package managers (`apt`, `yum`) are not available since agentOS runs a streamlined Linux environment rather than a full distribution. Native binaries that are not yet available in the registry (such as Go, Rust, or C++ toolchains) require a full [external sandbox](/agentos/docs/sandboxes). -See [Software](/docs/software) for how to install and configure available packages. +See [Software](/agentos/docs/software) for how to install and configure available packages. ### Lightweight Linux kernel diff --git a/website/src/content/docs/docs/models-and-credentials.mdx b/docs/content/docs/models-and-credentials.mdx similarity index 93% rename from website/src/content/docs/docs/models-and-credentials.mdx rename to docs/content/docs/models-and-credentials.mdx index 29f48b58c7..189612e6d8 100644 --- a/website/src/content/docs/docs/models-and-credentials.mdx +++ b/docs/content/docs/models-and-credentials.mdx @@ -36,4 +36,4 @@ Resolve each tenant's key and pass it at session creation: - Model selection belongs to the configured agent adapter. - AgentOS forwards the session environment and preserves the agent's native model behavior — no second model-selection layer. -- See your [agent](/docs/agents/pi) page for supported models and providers. +- See your [agent](/agentos/docs/agents/pi) page for supported models and providers. diff --git a/website/src/content/docs/docs/multiplayer.mdx b/docs/content/docs/multiplayer.mdx similarity index 100% rename from website/src/content/docs/docs/multiplayer.mdx rename to docs/content/docs/multiplayer.mdx diff --git a/website/src/content/docs/docs/networking.mdx b/docs/content/docs/networking.mdx similarity index 93% rename from website/src/content/docs/docs/networking.mdx rename to docs/content/docs/networking.mdx index 59d0b77b2c..d7fbf47d16 100644 --- a/website/src/content/docs/docs/networking.mdx +++ b/docs/content/docs/networking.mdx @@ -27,7 +27,7 @@ With the HTTP server running in the VM (above), send requests to it with `httpRe ## Preview URLs -Preview URLs are port forwarding for VM services: a time-limited, public URL that proxies HTTP to a port inside the VM, for browser or external access (use `httpRequest` for server-to-server). Preview creation is intentionally actor-only through the native `createPreviewUrl` and `expirePreviewUrl` actions; tokens survive sleep/wake and CORS is enabled. See [Security](/docs/security-model) for details. +Preview URLs are port forwarding for VM services: a time-limited, public URL that proxies HTTP to a port inside the VM, for browser or external access (use `httpRequest` for server-to-server). Preview creation is intentionally actor-only through the native `createPreviewUrl` and `expirePreviewUrl` actions; tokens survive sleep/wake and CORS is enabled. See [Security](/agentos/docs/security-model) for details. ### Create a preview URL @@ -62,4 +62,4 @@ const vm = agentOS({ }); ``` -See [Permissions](/docs/permissions) for the full configuration. +See [Permissions](/agentos/docs/permissions) for the full configuration. diff --git a/website/src/content/docs/docs/performance.mdx b/docs/content/docs/performance.mdx similarity index 100% rename from website/src/content/docs/docs/performance.mdx rename to docs/content/docs/performance.mdx diff --git a/website/src/content/docs/docs/permissions.mdx b/docs/content/docs/permissions.mdx similarity index 96% rename from website/src/content/docs/docs/permissions.mdx rename to docs/content/docs/permissions.mdx index f4bab14479..5adeec23d4 100644 --- a/website/src/content/docs/docs/permissions.mdx +++ b/docs/content/docs/permissions.mdx @@ -11,7 +11,7 @@ The sandbox permission policy is the kernel-level enforcement layer. Every guest - **A denied operation** is rejected with `EACCES` before any host resource is touched. - **Merged over a secure default**, so partial policies work. -For the higher-level agent tool-approval layer (human-in-the-loop, auto-approve), see [Approvals](/docs/approvals). +For the higher-level agent tool-approval layer (human-in-the-loop, auto-approve), see [Approvals](/agentos/docs/approvals). ## Defaults and merge semantics @@ -63,7 +63,7 @@ const permissions = { }; ``` -There is no typed `"ask"` mode. Interactive, human-in-the-loop approval lives in the higher-level [Approvals](/docs/approvals) layer, not the kernel policy. To block at the kernel level, use `"deny"`. +There is no typed `"ask"` mode. Interactive, human-in-the-loop approval lives in the higher-level [Approvals](/agentos/docs/approvals) layer, not the kernel policy. To block at the kernel level, use `"deny"`. ## Allow only specific filesystem paths diff --git a/website/src/content/docs/docs/persistence.mdx b/docs/content/docs/persistence.mdx similarity index 97% rename from website/src/content/docs/docs/persistence.mdx rename to docs/content/docs/persistence.mdx index 1720b5a6bb..611d33ad16 100644 --- a/website/src/content/docs/docs/persistence.mdx +++ b/docs/content/docs/persistence.mdx @@ -72,4 +72,4 @@ Live subscriptions resume only from new events. Ephemeral message deltas that ha The filesystem, core, and TypeScript actor independently own `agentos_fs_schema_version`, `agentos_core_schema_version`, and `agentos_actor_schema_version`. There is no shared schema-version table or global migration sequence. `agentos_actor_preview_tokens`, `agentos_actor_dynamic_mounts`, and `agentos_actor_linked_software` are actor-owned hosting metadata. -This per-VM database is trusted plaintext storage. Session environment values, MCP credentials, prompts, messages, and tool or permission payloads may be stored without encryption or redaction so they can survive sleep. Protect database and backup access accordingly. See [Sessions & Persistence](/docs/architecture/sessions-persistence/) for exact event storage and retention bounds. +This per-VM database is trusted plaintext storage. Session environment values, MCP credentials, prompts, messages, and tool or permission payloads may be stored without encryption or redaction so they can survive sleep. Protect database and backup access accordingly. See [Sessions & Persistence](/agentos/docs/architecture/sessions-persistence/) for exact event storage and retention bounds. diff --git a/website/src/content/docs/docs/processes.mdx b/docs/content/docs/processes.mdx similarity index 100% rename from website/src/content/docs/docs/processes.mdx rename to docs/content/docs/processes.mdx diff --git a/website/src/content/docs/docs/python.mdx b/docs/content/docs/python.mdx similarity index 89% rename from website/src/content/docs/docs/python.mdx rename to docs/content/docs/python.mdx index 0f031cdbd2..9a2473b9c6 100644 --- a/website/src/content/docs/docs/python.mdx +++ b/docs/content/docs/python.mdx @@ -10,7 +10,7 @@ Bash, JavaScript, and installed software. Letting an agent write code instead of chaining one tool call per step is called [Code Mode](https://blog.cloudflare.com/code-mode/). It has a few advantages over -driving [Bash](/docs/bash): +driving [Bash](/agentos/docs/bash): - **Fewer tokens**: Ten chained operations cost one round trip, not ten. - **Real data processing**: Comprehensions and `pandas` instead of `jq` and `awk`. @@ -84,19 +84,19 @@ and other executions. -See [Filesystem](/docs/filesystem), [Processes & Shells](/docs/processes), and -[Networking & Previews](/docs/networking). +See [Filesystem](/agentos/docs/filesystem), [Processes & Shells](/agentos/docs/processes), and +[Networking & Previews](/agentos/docs/networking). ## Bindings -Python calls [bindings](/docs/bindings) as normal commands via `subprocess`, so +Python calls [bindings](/agentos/docs/bindings) as normal commands via `subprocess`, so host credentials stay outside the VM. ## Permissions, limits, and timeouts -Every operation inherits the VM [permission policy](/docs/permissions) and -[resource limits](/docs/resource-limits). +Every operation inherits the VM [permission policy](/agentos/docs/permissions) and +[resource limits](/agentos/docs/resource-limits). diff --git a/website/src/content/docs/docs/quickstart.mdx b/docs/content/docs/quickstart.mdx similarity index 89% rename from website/src/content/docs/docs/quickstart.mdx rename to docs/content/docs/quickstart.mdx index 5346496bb3..d65361c77d 100644 --- a/website/src/content/docs/docs/quickstart.mdx +++ b/docs/content/docs/quickstart.mdx @@ -4,8 +4,9 @@ description: "Set up an agentOS actor, create a session, and run your first codi skill: true --- -import DeployTargets from '../../../components/DeployTargets.astro'; -import { AGENT_PROMPT } from '../../../components/marketing/agentPrompt'; +import { Hosting } from "@/components/docs/Hosting"; + +import { AGENT_PROMPT } from '@/data/agentPrompt';
Use this pre-built prompt to get started faster. @@ -65,7 +66,7 @@ import { AGENT_PROMPT } from '../../../components/marketing/agentPrompt'; 1. **Install** - **@rivet-dev/agentos** — Actor framework with built-in persistence and orchestration - - **@agentos-software/pi** — [Pi](https://github.com/mariozechner/pi-coding-agent) coding agent. [Claude Code](/docs/agents/claude), [Codex](/docs/agents/codex), and [OpenCode](/docs/agents/opencode) install the same way. + - **@agentos-software/pi** — [Pi](https://github.com/mariozechner/pi-coding-agent) coding agent. [Claude Code](/agentos/docs/agents/claude), [Codex](/agentos/docs/agents/codex), and [OpenCode](/agentos/docs/agents/opencode) install the same way. ```bash npm install @rivet-dev/agentos @agentos-software/pi @@ -97,24 +98,22 @@ import { AGENT_PROMPT } from '../../../components/marketing/agentPrompt'; npx tsx client.ts ``` - With the server running, open http://localhost:6420/ui to watch the VM in the [inspector](/docs/inspector): the live transcript, the filesystem, and its processes. + With the server running, open http://localhost:6420/ui to watch the VM in the [inspector](/agentos/docs/inspector): the live transcript, the filesystem, and its processes. 5. **Customize** Now that you have a working agent, customize it to fit your needs: - - **[Software](/docs/software)** — Install software packages inside the VM - - **[Filesystem](/docs/filesystem)** — Read, write, and manage files inside the VM - - **[Permissions & Resource Limits](/docs/permissions)** — Gate what the agent can do and cap its resource usage - - **[Bindings](/docs/bindings)** — Expose your JavaScript functions to agents as CLI commands + - **[Software](/agentos/docs/software)** — Install software packages inside the VM + - **[Filesystem](/agentos/docs/filesystem)** — Read, write, and manage files inside the VM + - **[Permissions & Resource Limits](/agentos/docs/permissions)** — Gate what the agent can do and cap its resource usage + - **[Bindings](/agentos/docs/bindings)** — Expose your JavaScript functions to agents as CLI commands 5. **Deploy** By default, agentOS runs locally with `npx rivetkit dev` — no infrastructure needed. To run in production, deploy to any of these targets: - - - See [Deployment](/docs/deployment) for managed, self-hosted, and direct VM options. + @@ -127,4 +126,4 @@ agentOS is in preview and the API is subject to change. If you run into issues, The same `@rivet-dev/agentos` package also exports `AgentOs.create()` for direct VM control without the actor lifecycle, multiplayer, or orchestration layer. -See the [direct VM API documentation](/docs/core) for reference. +See the [direct VM API documentation](/agentos/docs/core) for reference. diff --git a/website/src/content/docs/docs/resource-limits.mdx b/docs/content/docs/resource-limits.mdx similarity index 99% rename from website/src/content/docs/docs/resource-limits.mdx rename to docs/content/docs/resource-limits.mdx index 1f6d5f59a6..98f53eb568 100644 --- a/website/src/content/docs/docs/resource-limits.mdx +++ b/docs/content/docs/resource-limits.mdx @@ -105,5 +105,5 @@ bounded queues are tracked in a central limit registry that: protocol); set `AGENTOS_LOG=warn` (the default) to see near-limit warnings or `AGENTOS_LOG=debug` for live per-limit usage snapshots. -See [Limits & Observability](/docs/architecture/limits-and-observability) for the +See [Limits & Observability](/agentos/docs/architecture/limits-and-observability) for the full architecture. diff --git a/website/src/content/docs/docs/sandboxes.mdx b/docs/content/docs/sandboxes.mdx similarity index 95% rename from website/src/content/docs/docs/sandboxes.mdx rename to docs/content/docs/sandboxes.mdx index ec1150703b..a0ad3ed15a 100644 --- a/website/src/content/docs/docs/sandboxes.mdx +++ b/docs/content/docs/sandboxes.mdx @@ -6,14 +6,14 @@ skill: true Pair agentOS with a full sandbox on demand for heavy workloads. The sandbox filesystem mounts into the VM as a native directory, and its process management -is exposed as [bindings](/docs/bindings) — provider-agnostic through +is exposed as [bindings](/agentos/docs/bindings) — provider-agnostic through [Sandbox Agent](https://sandboxagent.dev). - agentOS covers most use cases; a sandbox adds a full Linux environment for special software. - Lazily start a sandbox only when a task needs it, then tear it down. - One agent session can mix lightweight coding with heavy system work. -- See [agentOS vs Sandbox](/docs/versus-sandbox) for the full comparison. +- See [agentOS vs Sandbox](/agentos/docs/versus-sandbox) for the full comparison. ## When to use a sandbox @@ -35,7 +35,7 @@ Ships as `@rivet-dev/agentos-sandbox`, working through two mechanisms: - **Filesystem mount** — projects the sandbox into the VM as a native directory. Read/write files through the mount. - **Bindings** — exposes sandbox process management as - [bindings](/docs/bindings). Run commands on the sandbox from the VM. + [bindings](/agentos/docs/bindings). Run commands on the sandbox from the VM. Both powered by [Sandbox Agent](https://sandboxagent.dev); swap providers without changing agent code. diff --git a/website/src/content/docs/docs/security-model.mdx b/docs/content/docs/security-model.mdx similarity index 91% rename from website/src/content/docs/docs/security-model.mdx rename to docs/content/docs/security-model.mdx index a2ea563755..7dd6a8bd0d 100644 --- a/website/src/content/docs/docs/security-model.mdx +++ b/docs/content/docs/security-model.mdx @@ -119,11 +119,11 @@ Each agentOS actor runs in its own isolated VM. Every guest syscall is mediated by the kernel and checked against the runtime's permission policy. Concretely, the kernel mediates: -- **Filesystem.** A virtual, in-memory filesystem. Guest reads and writes never reach the real host filesystem. Host data enters the VM only through the `files`, `mounts`, or `nodeModules` you configure explicitly. See [Filesystem](/docs/filesystem). -- **Processes.** `node:child_process` spawns kernel-managed guest processes, never real host processes. Children can only run the commands the VM mounts (WASM-backed `sh` and coreutils, V8-backed `node`). See [Processes](/docs/processes). -- **Network.** Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel socket table. Guest `fetch()` runs through undici inside the isolate and then through the kernel socket table; it never opens a real host socket. See [Networking](/docs/networking). +- **Filesystem.** A virtual, in-memory filesystem. Guest reads and writes never reach the real host filesystem. Host data enters the VM only through the `files`, `mounts`, or `nodeModules` you configure explicitly. See [Filesystem](/agentos/docs/filesystem). +- **Processes.** `node:child_process` spawns kernel-managed guest processes, never real host processes. Children can only run the commands the VM mounts (WASM-backed `sh` and coreutils, V8-backed `node`). See [Processes](/agentos/docs/processes). +- **Network.** Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel socket table. Guest `fetch()` runs through undici inside the isolate and then through the kernel socket table; it never opens a real host socket. See [Networking](/agentos/docs/networking). - **DNS, pipes, and PTYs** are likewise kernel-owned: no guest path reaches the host directly. -- **Bindings.** Registered [bindings](/docs/bindings) are the only sanctioned way to hand the guest a named host capability. The guest invokes a binding by name with JSON input, the call round-trips to the host handler, and only the handler's return value comes back. The guest never receives the underlying host access. +- **Bindings.** Registered [bindings](/agentos/docs/bindings) are the only sanctioned way to hand the guest a named host capability. The guest invokes a binding by name with JSON input, the call round-trips to the host handler, and only the handler's return value comes back. The guest never receives the underlying host access. ## What enters the VM @@ -144,7 +144,7 @@ Permissions are the capability gate at the boundary. They merge over a secure de permissions: { network: "allow" } ``` -A scope can be `"allow"`, `"deny"`, or a `{ default, rules }` policy that matches request patterns. Guest servers are reachable only over loopback inside the VM unless you exempt a port explicitly. See [Permissions](/docs/permissions) and [Networking](/docs/networking) for the full policy shape. +A scope can be `"allow"`, `"deny"`, or a `{ default, rules }` policy that matches request patterns. Guest servers are reachable only over loopback inside the VM unless you exempt a port explicitly. See [Permissions](/agentos/docs/permissions) and [Networking](/agentos/docs/networking) for the full policy shape. ## Resource and timing limits @@ -154,7 +154,7 @@ The VM bounds guest execution so runaway or hostile code cannot hang or exhaust - **Memory, CPU-time, and payload limits** are enforced by the VM. - **Timing-side-channel mitigation.** In the default mode, high-resolution clocks (`Date.now()`, `performance.now()`, `process.hrtime()`) are frozen within a run and `SharedArrayBuffer` is removed, to blunt timing side channels of the kind used in Spectre-style attacks. -See [Security & Auth](/docs/security-model) for resource limits, network control, and authentication setup. +See [Security & Auth](/agentos/docs/security-model) for resource limits, network control, and authentication setup. ## What agentOS guarantees @@ -171,15 +171,15 @@ The boundary protects the host from the guest. It does **not** harden your host - Hardening the host process and deployment environment. For internet-facing workloads that take untrusted input, run your host inside an already-hardened environment (for example AWS Lambda, Google Cloud Run, or a similar sandboxed platform). - Validating authentication tokens in `onBeforeConnect`. -- Scoping [permissions](/docs/permissions) appropriately for your use case. -- Managing API keys and secrets on the host side (see [Models & Credentials](/docs/models-and-credentials)). -- Configuring [resource limits and network controls](/docs/security-model) to match your threat model. +- Scoping [permissions](/agentos/docs/permissions) appropriately for your use case. +- Managing API keys and secrets on the host side (see [Models & Credentials](/agentos/docs/models-and-credentials)). +- Configuring [resource limits and network controls](/agentos/docs/security-model) to match your threat model. - Choosing your blast radius: prefer a fresh VM per untrusted or high-risk task so an escape attempt cannot outlive a single VM. The boundary contains guest code, but you still own the host. Treat the host process as trusted infrastructure and harden it. ## Further reading -- [Security configuration](/docs/security-model) for resource limits, network control, and authentication setup -- [Permissions](/docs/permissions) for agent tool-use approval patterns -- [agentOS vs Sandbox](/docs/versus-sandbox) for when to escalate to a full sandbox +- [Security configuration](/agentos/docs/security-model) for resource limits, network control, and authentication setup +- [Permissions](/agentos/docs/permissions) for agent tool-use approval patterns +- [agentOS vs Sandbox](/agentos/docs/versus-sandbox) for when to escalate to a full sandbox diff --git a/website/src/content/docs/docs/sessions.mdx b/docs/content/docs/sessions.mdx similarity index 96% rename from website/src/content/docs/docs/sessions.mdx rename to docs/content/docs/sessions.mdx index 9564db5240..7b4e830071 100644 --- a/website/src/content/docs/docs/sessions.mdx +++ b/docs/content/docs/sessions.mdx @@ -8,7 +8,7 @@ AgentOS sessions are durable records backed by the VM's SQLite database. - The public session ID is stable across VM sleep and adapter restarts. - The adapter's private ACP session ID stays internal. -- The [inspector](/docs/inspector)'s Transcript tab renders the same session stream live, with a composer for prompting sessions by hand. +- The [inspector](/agentos/docs/inspector)'s Transcript tab renders the same session stream live, with a composer for prompting sessions by hand. ## Open a session @@ -42,7 +42,7 @@ Input fields: `agent`, `cwd`, `additionalDirectories`, `env`, `mcpServers`, reads `.mcp.json` from its AgentOS home). - Install local MCP server packages before opening the session so first-run package-manager output can't corrupt a stdio handshake. -- See the [agent guide](/docs/agents/pi) for adapter specifics. +- See the [agent guide](/agentos/docs/agents/pi) for adapter specifics. diff --git a/website/src/content/docs/docs/software.mdx b/docs/content/docs/software.mdx similarity index 79% rename from website/src/content/docs/docs/software.mdx rename to docs/content/docs/software.mdx index a991eb80c7..e2858a4be7 100644 --- a/website/src/content/docs/docs/software.mdx +++ b/docs/content/docs/software.mdx @@ -30,4 +30,4 @@ Browse all available software packages on the [Registry](/registry). ## Custom Software -Package your own agents, command packages, and WASM commands. See [Software Definition](/docs/custom-software/definition) to define a package, and [Building Binaries](/docs/custom-software/building-wasm) to compile WASM commands from source in the [agentos registry](https://github.com/rivet-dev/agentos/tree/main/registry). +Package your own agents, command packages, and WASM commands. See [Software Definition](/agentos/docs/custom-software/definition) to define a package, and [Building Binaries](/agentos/docs/custom-software/building-wasm) to compile WASM commands from source in the [agentos registry](https://github.com/rivet-dev/agentos/tree/main/registry). diff --git a/website/src/content/docs/docs/system-prompt.mdx b/docs/content/docs/system-prompt.mdx similarity index 100% rename from website/src/content/docs/docs/system-prompt.mdx rename to docs/content/docs/system-prompt.mdx diff --git a/website/src/content/docs/docs/versus-sandbox.mdx b/docs/content/docs/versus-sandbox.mdx similarity index 74% rename from website/src/content/docs/docs/versus-sandbox.mdx rename to docs/content/docs/versus-sandbox.mdx index 1d321a87bd..7435de08a5 100644 --- a/website/src/content/docs/docs/versus-sandbox.mdx +++ b/docs/content/docs/versus-sandbox.mdx @@ -4,9 +4,9 @@ description: "When to use the lightweight agentOS VM, a full sandbox, or both to skill: true --- -- **agentOS** is a lightweight VM that runs inside your process. Near-zero cold start, low memory, direct backend integration via [bindings](/docs/bindings). +- **agentOS** is a lightweight VM that runs inside your process. Near-zero cold start, low memory, direct backend integration via [bindings](/agentos/docs/bindings). - **Sandboxes** are full Linux environments with root access, system packages, and native binary support. -- **You can use both.** agentOS works with sandboxes through the [external sandbox extension](/docs/sandboxes). Agents run in the lightweight VM by default and spin up a full sandbox on demand. +- **You can use both.** agentOS works with sandboxes through the [external sandbox extension](/agentos/docs/sandboxes). Agents run in the lightweight VM by default and spin up a full sandbox on demand. ## Comparison @@ -14,8 +14,8 @@ skill: true |---|---|---| | **Cost** | Very low. Runs in your process. | Pay per second of uptime. | | **Startup** | Near-zero cold start (~6 ms). | Seconds to spin up. | -| **Backend integration** | Direct. [Bindings](/docs/bindings) call your functions with zero latency. | Indirect. Requires network calls back to your backend. | -| **Credentials** | Stay on the host. [Bindings](/docs/bindings) run your functions server-side; agents see only inputs and outputs. | Must be injected into the sandbox environment. | +| **Backend integration** | Direct. [Bindings](/agentos/docs/bindings) call your functions with zero latency. | Indirect. Requires network calls back to your backend. | +| **Credentials** | Stay on the host. [Bindings](/agentos/docs/bindings) run your functions server-side; agents see only inputs and outputs. | Must be injected into the sandbox environment. | | **Permissions** | Granular, deny-by-default. | Coarse-grained (container-level). | | **Infrastructure** | `npm install` | Vendor account + API keys. | | **Best for** | Coding, file manipulation, scripting, API calls, orchestration. | Browsers, desktop automation, native compilation, dev servers. | @@ -43,7 +43,7 @@ Spin up a sandbox when the workload needs a real Linux kernel: ### Both together -Use agentOS with [external sandboxes](/docs/sandboxes) for workflows that need both: +Use agentOS with [external sandboxes](/agentos/docs/sandboxes) for workflows that need both: - Agent runs in the agentOS VM with full access to bindings and permissions - Sandbox spins up on demand for heavy tasks diff --git a/website/src/content/docs/docs/workflows.mdx b/docs/content/docs/workflows.mdx similarity index 100% rename from website/src/content/docs/docs/workflows.mdx rename to docs/content/docs/workflows.mdx diff --git a/website/src/content/docs/docs/frameworks/flue.mdx b/docs/content/integrations/flue.mdx similarity index 95% rename from website/src/content/docs/docs/frameworks/flue.mdx rename to docs/content/integrations/flue.mdx index 6c89640fc0..0fba7a70d8 100644 --- a/website/src/content/docs/docs/frameworks/flue.mdx +++ b/docs/content/integrations/flue.mdx @@ -4,7 +4,7 @@ description: "Use agentOS as the durable sandbox backend for Flue." skill: true --- -import DeployTargets from '../../../../components/DeployTargets.astro'; +import DeployTargets from '@/components/docs/DeployTargets.astro'; {/* Sync policy: examples/flue and examples/vercel-eve in this repository are the @@ -107,7 +107,7 @@ agentOS persists the VM filesystem, including `/workspace`, to Rivet Actor stora ### Virtual machine -See the `agentOS()` [configuration reference](/docs/core#configuration-reference) to configure the VM. +See the `agentOS()` [configuration reference](/agentos/docs/core#configuration-reference) to configure the VM. ### Flue sandbox diff --git a/docs/content/integrations/index.mdx b/docs/content/integrations/index.mdx new file mode 100644 index 0000000000..ce9deeabd1 --- /dev/null +++ b/docs/content/integrations/index.mdx @@ -0,0 +1,9 @@ +--- +title: "Integrations" +description: "Frameworks and platforms that work with agentOS." +--- + +import { IntegrationCards } from "@/components/docs/IntegrationCards"; + + + diff --git a/website/src/content/docs/docs/frameworks/rivet.mdx b/docs/content/integrations/rivet.mdx similarity index 65% rename from website/src/content/docs/docs/frameworks/rivet.mdx rename to docs/content/integrations/rivet.mdx index c578909223..691b67cd82 100644 --- a/website/src/content/docs/docs/frameworks/rivet.mdx +++ b/docs/content/integrations/rivet.mdx @@ -4,7 +4,7 @@ description: "Run agentOS natively as Rivet Actors." skill: true --- -import DeployTargets from '../../../../components/DeployTargets.astro'; +import DeployTargets from '@/components/docs/DeployTargets.astro'; Rivet is agentOS's native framework. The `agentOS()` function returns an ordinary [Rivet Actor](https://rivet.dev/docs/actors), so each agentOS VM is a directly addressable actor with its own durable filesystem, state, and session history—no adapter layer required. @@ -60,11 +60,11 @@ ANTHROPIC_API_KEY=... npx tsx client.ts Because an agentOS VM is a Rivet Actor, you can compose it with Rivet's orchestration primitives: -- **[Durable workflows](/docs/workflows)** — Run multi-step agent tasks that retry and resume after crashes. -- **[Multiplayer agents](/docs/multiplayer)** — Stream agent output to multiple connected clients in real time. -- **[Agent-to-agent systems](/docs/agent-to-agent)** — Connect isolated agents through typed bindings and durable pipelines. -- **[Scheduled agents](/docs/cron)** — Run commands and agent sessions on timers or cron schedules. -- **[Human-in-the-loop flows](/docs/approvals)** — Pause for tool approval and resume from durable event history. +- **[Durable workflows](/agentos/docs/workflows)** — Run multi-step agent tasks that retry and resume after crashes. +- **[Multiplayer agents](/agentos/docs/multiplayer)** — Stream agent output to multiple connected clients in real time. +- **[Agent-to-agent systems](/agentos/docs/agent-to-agent)** — Connect isolated agents through typed bindings and durable pipelines. +- **[Scheduled agents](/agentos/docs/cron)** — Run commands and agent sessions on timers or cron schedules. +- **[Human-in-the-loop flows](/agentos/docs/approvals)** — Pause for tool approval and resume from durable event history. @@ -80,4 +80,4 @@ Deploy to one of the supported platforms: ## Learn more -See the [agentOS quickstart](/docs/quickstart) for VM configuration and the [Rivet Actor documentation](https://rivet.dev/docs/actors) for state, actions, events, queues, workflows, and deployment. +See the [agentOS quickstart](/agentos/docs/quickstart) for VM configuration and the [Rivet Actor documentation](https://rivet.dev/docs/actors) for state, actions, events, queues, workflows, and deployment. diff --git a/website/src/content/docs/docs/frameworks/vercel-eve.mdx b/docs/content/integrations/vercel-eve.mdx similarity index 94% rename from website/src/content/docs/docs/frameworks/vercel-eve.mdx rename to docs/content/integrations/vercel-eve.mdx index c810df4564..8a8579c02e 100644 --- a/website/src/content/docs/docs/frameworks/vercel-eve.mdx +++ b/docs/content/integrations/vercel-eve.mdx @@ -4,7 +4,7 @@ description: "Run Vercel Eve with agentOS and Rivet World." skill: true --- -import DeployTargets from '../../../../components/DeployTargets.astro'; +import DeployTargets from '@/components/docs/DeployTargets.astro'; {/* Sync policy: examples/flue and examples/vercel-eve in this repository are the @@ -109,7 +109,7 @@ By default, agentOS runs locally with `npx rivetkit dev` — no infrastructure n -See [Deployment](/docs/deployment) for managed, self-hosted, and agentOS Core options. +See [Deployment](/agentos/self-host) for managed, self-hosted, and agentOS Core options. @@ -123,7 +123,7 @@ agentOS persists the VM filesystem, including `/workspace`, to Rivet Actor stora ### Virtual Machine -See the `agentOS()` [configuration reference](/docs/core#configuration-reference) to configure the VM. +See the `agentOS()` [configuration reference](/agentos/docs/core#configuration-reference) to configure the VM. ### Eve Sandbox Backend diff --git a/docs/content/use-cases/index.mdx b/docs/content/use-cases/index.mdx new file mode 100644 index 0000000000..cfc0fe8d91 --- /dev/null +++ b/docs/content/use-cases/index.mdx @@ -0,0 +1,84 @@ +--- +title: "Use Cases" +description: "What people build with agentOS." +--- + +agentOS runs coding agents inside isolated VMs with a real filesystem, shell, +and process model. These are the shapes that keep coming up. + +## Programming Agents + +Purpose-built for agents that write, test, and deploy code autonomously. + +- Native file system access with git support +- Shell execution with full toolchain access +- Package installation and dependency management +- Test runner integration + +**Example:** An agent that takes a GitHub issue, writes the fix, runs tests, and opens a pull request. + +## Background Agents + +Long-running agents that operate asynchronously, processing tasks over hours or days without human intervention. + +- Persistent state survives crashes and restarts +- Queue commands while agents work +- Resume from exactly where they left off +- Monitor progress in real-time + +**Example:** A code migration agent that refactors a large codebase over several hours, committing changes incrementally. + +## Evals + +Run agent evaluations and benchmarks at scale without spinning up expensive sandboxes for each test. + +- Low memory per instance compared to sandboxes +- Near-zero cold starts for rapid iteration +- Deterministic replay for debugging +- Cost-effective at thousands of runs + +**Example:** Evaluating 10,000 agent responses in parallel to measure performance across different prompts. + +## Multi-Agent Systems + +Coordinate multiple agents working together on complex tasks with shared state and communication. + +- Shared file systems between agents +- Real-time inter-agent messaging +- Workflow orchestration primitives +- Centralized observability + +**Example:** A team of agents where one researches, one writes, and one reviews, all collaborating on a document. + +## Data Processing + +Run ETL pipelines, data transformations, and analysis tasks with agent intelligence. + +- Stream processing capabilities +- Database connections and queries +- File format conversion +- Incremental processing + +**Example:** An agent that ingests raw data, cleans it, runs analysis, and generates reports on a schedule. + +## Workflow Automation + +Chain agent tasks into complex workflows with conditional logic and human-in-the-loop steps. + +- Durable workflow execution +- Retry and error handling +- Scheduled and triggered runs +- Approval gates and notifications + +**Example:** A hiring workflow where agents screen resumes, schedule interviews, and prepare onboarding docs. + +## Personal Agents + +Lightweight agents that assist individual users with daily tasks and workflows. + +- Low resource overhead for personal use +- Local-first with optional cloud sync +- Custom tool integration +- Privacy-focused execution + +**Example:** A personal agent that organizes your calendar, drafts emails, and manages your todo list. diff --git a/website/public/images/registry/bash.svg b/docs/public/images/registry/bash.svg similarity index 100% rename from website/public/images/registry/bash.svg rename to docs/public/images/registry/bash.svg diff --git a/website/public/images/registry/browserbase.svg b/docs/public/images/registry/browserbase.svg similarity index 100% rename from website/public/images/registry/browserbase.svg rename to docs/public/images/registry/browserbase.svg diff --git a/website/public/images/registry/chrome.svg b/docs/public/images/registry/chrome.svg similarity index 100% rename from website/public/images/registry/chrome.svg rename to docs/public/images/registry/chrome.svg diff --git a/website/public/images/registry/claude-code.svg b/docs/public/images/registry/claude-code.svg similarity index 100% rename from website/public/images/registry/claude-code.svg rename to docs/public/images/registry/claude-code.svg diff --git a/website/public/images/registry/cloudflare.svg b/docs/public/images/registry/cloudflare.svg similarity index 100% rename from website/public/images/registry/cloudflare.svg rename to docs/public/images/registry/cloudflare.svg diff --git a/website/public/images/registry/codex.svg b/docs/public/images/registry/codex.svg similarity index 100% rename from website/public/images/registry/codex.svg rename to docs/public/images/registry/codex.svg diff --git a/website/public/images/registry/computesdk.svg b/docs/public/images/registry/computesdk.svg similarity index 100% rename from website/public/images/registry/computesdk.svg rename to docs/public/images/registry/computesdk.svg diff --git a/website/public/images/registry/coreutils.svg b/docs/public/images/registry/coreutils.svg similarity index 100% rename from website/public/images/registry/coreutils.svg rename to docs/public/images/registry/coreutils.svg diff --git a/website/public/images/registry/curl.svg b/docs/public/images/registry/curl.svg similarity index 100% rename from website/public/images/registry/curl.svg rename to docs/public/images/registry/curl.svg diff --git a/website/public/images/registry/daytona.svg b/docs/public/images/registry/daytona.svg similarity index 100% rename from website/public/images/registry/daytona.svg rename to docs/public/images/registry/daytona.svg diff --git a/website/public/images/registry/deploy-aws-ecs.svg b/docs/public/images/registry/deploy-aws-ecs.svg similarity index 100% rename from website/public/images/registry/deploy-aws-ecs.svg rename to docs/public/images/registry/deploy-aws-ecs.svg diff --git a/website/public/images/registry/deploy-custom.svg b/docs/public/images/registry/deploy-custom.svg similarity index 100% rename from website/public/images/registry/deploy-custom.svg rename to docs/public/images/registry/deploy-custom.svg diff --git a/website/public/images/registry/deploy-gcp-cloud-run.svg b/docs/public/images/registry/deploy-gcp-cloud-run.svg similarity index 100% rename from website/public/images/registry/deploy-gcp-cloud-run.svg rename to docs/public/images/registry/deploy-gcp-cloud-run.svg diff --git a/website/public/images/registry/deploy-hetzner.svg b/docs/public/images/registry/deploy-hetzner.svg similarity index 100% rename from website/public/images/registry/deploy-hetzner.svg rename to docs/public/images/registry/deploy-hetzner.svg diff --git a/website/public/images/registry/deploy-kubernetes.svg b/docs/public/images/registry/deploy-kubernetes.svg similarity index 100% rename from website/public/images/registry/deploy-kubernetes.svg rename to docs/public/images/registry/deploy-kubernetes.svg diff --git a/website/public/images/registry/deploy-railway.svg b/docs/public/images/registry/deploy-railway.svg similarity index 100% rename from website/public/images/registry/deploy-railway.svg rename to docs/public/images/registry/deploy-railway.svg diff --git a/website/public/images/registry/deploy-rivet-compute.svg b/docs/public/images/registry/deploy-rivet-compute.svg similarity index 100% rename from website/public/images/registry/deploy-rivet-compute.svg rename to docs/public/images/registry/deploy-rivet-compute.svg diff --git a/website/public/images/registry/deploy-vercel.svg b/docs/public/images/registry/deploy-vercel.svg similarity index 100% rename from website/public/images/registry/deploy-vercel.svg rename to docs/public/images/registry/deploy-vercel.svg diff --git a/website/public/images/registry/deploy-vm-and-bare-metal.svg b/docs/public/images/registry/deploy-vm-and-bare-metal.svg similarity index 100% rename from website/public/images/registry/deploy-vm-and-bare-metal.svg rename to docs/public/images/registry/deploy-vm-and-bare-metal.svg diff --git a/website/public/images/registry/diffutils.svg b/docs/public/images/registry/diffutils.svg similarity index 100% rename from website/public/images/registry/diffutils.svg rename to docs/public/images/registry/diffutils.svg diff --git a/website/public/images/registry/docker.svg b/docs/public/images/registry/docker.svg similarity index 100% rename from website/public/images/registry/docker.svg rename to docs/public/images/registry/docker.svg diff --git a/website/public/images/registry/duckdb.svg b/docs/public/images/registry/duckdb.svg similarity index 100% rename from website/public/images/registry/duckdb.svg rename to docs/public/images/registry/duckdb.svg diff --git a/website/public/images/registry/e2b.svg b/docs/public/images/registry/e2b.svg similarity index 100% rename from website/public/images/registry/e2b.svg rename to docs/public/images/registry/e2b.svg diff --git a/website/public/images/registry/findutils.svg b/docs/public/images/registry/findutils.svg similarity index 100% rename from website/public/images/registry/findutils.svg rename to docs/public/images/registry/findutils.svg diff --git a/website/public/images/registry/gawk.svg b/docs/public/images/registry/gawk.svg similarity index 100% rename from website/public/images/registry/gawk.svg rename to docs/public/images/registry/gawk.svg diff --git a/website/public/images/registry/git.svg b/docs/public/images/registry/git.svg similarity index 100% rename from website/public/images/registry/git.svg rename to docs/public/images/registry/git.svg diff --git a/website/public/images/registry/google-drive.svg b/docs/public/images/registry/google-drive.svg similarity index 100% rename from website/public/images/registry/google-drive.svg rename to docs/public/images/registry/google-drive.svg diff --git a/website/public/images/registry/grep.svg b/docs/public/images/registry/grep.svg similarity index 100% rename from website/public/images/registry/grep.svg rename to docs/public/images/registry/grep.svg diff --git a/website/public/images/registry/gzip.svg b/docs/public/images/registry/gzip.svg similarity index 100% rename from website/public/images/registry/gzip.svg rename to docs/public/images/registry/gzip.svg diff --git a/website/public/images/registry/jq.svg b/docs/public/images/registry/jq.svg similarity index 100% rename from website/public/images/registry/jq.svg rename to docs/public/images/registry/jq.svg diff --git a/website/public/images/registry/linux.svg b/docs/public/images/registry/linux.svg similarity index 100% rename from website/public/images/registry/linux.svg rename to docs/public/images/registry/linux.svg diff --git a/website/public/images/registry/modal.svg b/docs/public/images/registry/modal.svg similarity index 100% rename from website/public/images/registry/modal.svg rename to docs/public/images/registry/modal.svg diff --git a/website/public/images/registry/nodejs.svg b/docs/public/images/registry/nodejs.svg similarity index 100% rename from website/public/images/registry/nodejs.svg rename to docs/public/images/registry/nodejs.svg diff --git a/website/public/images/registry/opencode.svg b/docs/public/images/registry/opencode.svg similarity index 100% rename from website/public/images/registry/opencode.svg rename to docs/public/images/registry/opencode.svg diff --git a/website/public/images/registry/pi.svg b/docs/public/images/registry/pi.svg similarity index 100% rename from website/public/images/registry/pi.svg rename to docs/public/images/registry/pi.svg diff --git a/website/public/images/registry/python.svg b/docs/public/images/registry/python.svg similarity index 100% rename from website/public/images/registry/python.svg rename to docs/public/images/registry/python.svg diff --git a/website/public/images/registry/s3.svg b/docs/public/images/registry/s3.svg similarity index 100% rename from website/public/images/registry/s3.svg rename to docs/public/images/registry/s3.svg diff --git a/website/public/images/registry/sed.svg b/docs/public/images/registry/sed.svg similarity index 100% rename from website/public/images/registry/sed.svg rename to docs/public/images/registry/sed.svg diff --git a/website/public/images/registry/sprites.svg b/docs/public/images/registry/sprites.svg similarity index 100% rename from website/public/images/registry/sprites.svg rename to docs/public/images/registry/sprites.svg diff --git a/website/public/images/registry/sqlite3.svg b/docs/public/images/registry/sqlite3.svg similarity index 100% rename from website/public/images/registry/sqlite3.svg rename to docs/public/images/registry/sqlite3.svg diff --git a/website/public/images/registry/ssh.svg b/docs/public/images/registry/ssh.svg similarity index 100% rename from website/public/images/registry/ssh.svg rename to docs/public/images/registry/ssh.svg diff --git a/website/public/images/registry/super-memory.svg b/docs/public/images/registry/super-memory.svg similarity index 100% rename from website/public/images/registry/super-memory.svg rename to docs/public/images/registry/super-memory.svg diff --git a/website/public/images/registry/tar.svg b/docs/public/images/registry/tar.svg similarity index 100% rename from website/public/images/registry/tar.svg rename to docs/public/images/registry/tar.svg diff --git a/website/public/images/registry/vercel.svg b/docs/public/images/registry/vercel.svg similarity index 100% rename from website/public/images/registry/vercel.svg rename to docs/public/images/registry/vercel.svg diff --git a/website/public/images/registry/vim.svg b/docs/public/images/registry/vim.svg similarity index 100% rename from website/public/images/registry/vim.svg rename to docs/public/images/registry/vim.svg diff --git a/website/public/images/registry/wget.svg b/docs/public/images/registry/wget.svg similarity index 100% rename from website/public/images/registry/wget.svg rename to docs/public/images/registry/wget.svg diff --git a/website/src/generated/registry.json b/docs/registry.json similarity index 100% rename from website/src/generated/registry.json rename to docs/registry.json diff --git a/docs/sidebar.json b/docs/sidebar.json new file mode 100644 index 0000000000..d7b25edda8 --- /dev/null +++ b/docs/sidebar.json @@ -0,0 +1,354 @@ +{ + "docs": [ + { + "title": "General", + "pages": [ + { + "title": "Overview", + "href": "/agentos/docs", + "icon": "faSquareInfo" + }, + { + "title": "Quickstart", + "href": "/agentos/docs/quickstart", + "icon": "faForwardFast" + }, + { + "title": "Crash Course", + "href": "/agentos/docs/crash-course", + "icon": "faLightbulb" + }, + { + "title": "Inspector", + "href": "/agentos/docs/inspector", + "icon": "faMagnifyingGlass" + }, + { + "title": "agentOS vs Sandbox", + "href": "/agentos/docs/versus-sandbox", + "icon": "faScaleBalanced" + } + ] + }, + { + "title": "Agent", + "pages": [ + { + "title": "Agents", + "collapsible": true, + "icon": "faRobot", + "pages": [ + { + "title": "Pi", + "href": "/agentos/docs/agents/pi", + "icon": { + "src": "/images/registry/pi.svg" + } + }, + { + "title": "ClaudeCode", + "href": "/agentos/docs/agents/claude", + "badge": "Beta", + "icon": { + "src": "/images/registry/claude-code.svg" + } + }, + { + "title": "Codex", + "href": "/agentos/docs/agents/codex", + "badge": "Beta", + "icon": { + "src": "/images/registry/codex.svg" + } + }, + { + "title": "OpenCode", + "href": "/agentos/docs/agents/opencode", + "icon": { + "src": "/images/registry/opencode.svg" + } + }, + { + "title": "Custom Agents", + "href": "/agentos/docs/agents/custom", + "icon": "faWrench" + } + ] + }, + { + "title": "Sessions & Transcripts", + "href": "/agentos/docs/sessions", + "icon": "faMessages" + }, + { + "title": "Approvals", + "href": "/agentos/docs/approvals", + "icon": "faCheck" + }, + { + "title": "Models & Credentials", + "href": "/agentos/docs/models-and-credentials", + "icon": "faKey" + } + ] + }, + { + "title": "Execution", + "pages": [ + { + "title": "Bash", + "href": "/agentos/docs/bash", + "icon": "faTerminal" + }, + { + "title": "Node.js", + "href": "/agentos/docs/javascript", + "icon": "faNodeJs" + }, + { + "title": "Python", + "href": "/agentos/docs/python", + "icon": "faPython" + } + ] + }, + { + "title": "Orchestration", + "pages": [ + { + "title": "Multiplayer", + "href": "/agentos/docs/multiplayer", + "icon": "faTowerBroadcast" + }, + { + "title": "Workflows & Graphs", + "href": "/agentos/docs/workflows", + "icon": "faDiagramNext" + }, + { + "title": "Crons & Loops", + "href": "/agentos/docs/cron", + "icon": "faClock" + }, + { + "title": "Agent-to-Agent", + "href": "/agentos/docs/agent-to-agent", + "icon": "faArrowsLeftRight" + } + ] + }, + { + "title": "Operating System", + "pages": [ + { + "title": "Software", + "href": "/agentos/docs/software", + "icon": "faDownload" + }, + { + "title": "Filesystem", + "href": "/agentos/docs/filesystem", + "icon": "faFloppyDisk" + }, + { + "title": "Processes & Shells", + "href": "/agentos/docs/processes", + "icon": "faTerminal" + }, + { + "title": "Networking & Previews", + "href": "/agentos/docs/networking", + "icon": "faGlobe" + }, + { + "title": "Permissions", + "href": "/agentos/docs/permissions", + "icon": "faKey" + }, + { + "title": "Resource Limits", + "href": "/agentos/docs/resource-limits", + "icon": "faGauge" + } + ] + }, + { + "title": "Extensions", + "pages": [ + { + "title": "Custom Bindings", + "href": "/agentos/docs/bindings", + "icon": "faWrench" + }, + { + "title": "Browser Automation", + "href": "/agentos/docs/browser", + "badge": "Beta", + "icon": "faWindowMaximize" + }, + { + "title": "External Sandboxes", + "href": "/agentos/docs/sandboxes", + "badge": "Beta", + "icon": "faHardDrive" + } + ] + }, + { + "title": "Reference", + "pages": [ + { + "title": "Authentication", + "href": "/agentos/docs/authentication" + }, + { + "title": "Custom Software", + "collapsible": true, + "pages": [ + { + "title": "Definition", + "href": "/agentos/docs/custom-software/definition" + }, + { + "title": "Building Binaries", + "href": "/agentos/docs/custom-software/building-wasm" + }, + { + "title": "Request Software", + "href": "https://github.com/rivet-dev/agentos/issues/new/choose", + "external": true, + "target": "_blank" + } + ] + }, + { + "title": "Architecture", + "collapsible": true, + "pages": [ + { + "title": "Overview", + "href": "/agentos/docs/architecture" + }, + { + "title": "Security Model", + "href": "/agentos/docs/security-model" + }, + { + "title": "Limitations", + "href": "/agentos/docs/limitations" + }, + { + "title": "Advanced", + "collapsible": true, + "pages": [ + { + "title": "Agent Sessions", + "href": "/agentos/docs/architecture/agent-sessions" + }, + { + "title": "Agent SDK Snapshots", + "href": "/agentos/docs/architecture/agent-sdk-snapshots" + }, + { + "title": "Sessions & Persistence", + "href": "/agentos/docs/architecture/sessions-persistence" + }, + { + "title": "Processes", + "href": "/agentos/docs/architecture/processes" + }, + { + "title": "Filesystem", + "href": "/agentos/docs/architecture/filesystem" + }, + { + "title": "Networking", + "href": "/agentos/docs/architecture/networking" + }, + { + "title": "TLS & SSL", + "href": "/agentos/docs/architecture/tls-ssl" + }, + { + "title": "JavaScript Executor & Reactor", + "href": "/agentos/docs/architecture/javascript-executor" + }, + { + "title": "POSIX Syscalls", + "href": "/agentos/docs/architecture/posix-syscalls" + }, + { + "title": "Packages & Command Resolution", + "href": "/agentos/docs/architecture/packages-and-command-resolution" + }, + { + "title": "Compiler Toolchain", + "href": "/agentos/docs/architecture/compiler-toolchain" + }, + { + "title": "Limits & Observability", + "href": "/agentos/docs/architecture/limits-and-observability" + }, + { + "title": "System Prompt", + "href": "/agentos/docs/system-prompt" + }, + { + "title": "Persistence & Sleep", + "href": "/agentos/docs/persistence" + } + ] + } + ] + }, + { + "title": "More", + "collapsible": true, + "pages": [ + { + "title": "Direct VM SDK", + "href": "/agentos/docs/core" + }, + { + "title": "Debugging", + "href": "/agentos/docs/debugging" + }, + { + "title": "Performance", + "href": "/agentos/docs/performance" + } + ] + } + ] + } + ], + "integrations": [ + { + "title": "General", + "pages": [ + { + "title": "Overview", + "href": "/agentos/integrations", + "icon": "faSquareInfo" + } + ] + }, + { + "title": "Frameworks", + "pages": [ + { + "title": "Flue", + "href": "/agentos/integrations/flue" + }, + { + "title": "Rivet", + "href": "/agentos/integrations/rivet" + }, + { + "title": "Vercel Eve", + "href": "/agentos/integrations/vercel-eve" + } + ] + } + ] +} diff --git a/website/scripts/gen-registry.mjs b/scripts/gen-registry.mjs similarity index 86% rename from website/scripts/gen-registry.mjs rename to scripts/gen-registry.mjs index cc852dcd85..408ff156ae 100644 --- a/website/scripts/gen-registry.mjs +++ b/scripts/gen-registry.mjs @@ -1,4 +1,7 @@ -// Generates src/generated/registry.json from the monorepo's software/ catalog. +// Generates docs/registry.json from this repo's software/ catalog. +// +// The output ships in the docs bundle; rivet-website copies it in at assemble +// time, so the catalog stays owned by the repo that defines it. // // A package is listed iff its agentos-package.json has a `registry` block with // both `title` and `description` — no fallbacks. Everything else is derived: @@ -12,12 +15,12 @@ // Docker build, whose context is website/ only), the committed file is used // as-is. import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; -import { dirname, join } from "node:path"; +import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; -const websiteDir = dirname(dirname(fileURLToPath(import.meta.url))); -const softwareRoot = join(websiteDir, "..", "software"); -const outPath = join(websiteDir, "src", "generated", "registry.json"); +const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const softwareRoot = join(repoRoot, "software"); +const outPath = join(repoRoot, "docs", "registry.json"); if (!existsSync(softwareRoot)) { if (existsSync(outPath)) { @@ -79,7 +82,7 @@ for (const entry of entries) { } seen.add(entry.slug); if (entry.image) { - const imagePath = join(websiteDir, "public", entry.image); + const imagePath = join(repoRoot, "docs", "public", entry.image); if (!existsSync(imagePath)) { console.error(`gen-registry: ${entry.slug} references missing image ${entry.image}`); process.exit(1); diff --git a/website/.dockerignore b/website/.dockerignore deleted file mode 100644 index d2053be7b0..0000000000 --- a/website/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.astro -*.log diff --git a/website/.gitignore b/website/.gitignore deleted file mode 100644 index c1e83d7788..0000000000 --- a/website/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Auto-generated TypeDoc API reference (built by `pnpm run docs:api`, served at /api) -public/api/ -vendor/ diff --git a/website/Dockerfile b/website/Dockerfile deleted file mode 100644 index 4354e3dae5..0000000000 --- a/website/Dockerfile +++ /dev/null @@ -1,78 +0,0 @@ -# Build the Astro site. Railway (and most platforms) use the repository root as -# the Docker build context, so paths here are written relative to the repo root -# (the site lives in website/). The root .dockerignore narrows the context to -# website/ plus the agentos SDK source (needed by the typedoc API-gen step), so -# the multi-GB monorepo is never uploaded. The shared docs theme -# (@rivet-dev/docs-theme) is git-cloned + built from GitHub at a pinned sha -# (the committed website deps are workspace:*/local for dev — we rewrite them -# to the clone here). -FROM node:22-alpine AS build -WORKDIR /app -RUN apk add --no-cache git && npm install -g pnpm@9 - -# Clone + build the shared docs theme at a pinned sha. The theme's dist/ is -# gitignored so we build it; its vendored @rivet-gg/components+icons come along. -ARG DOCS_THEME_SHA=450c498555135098c6a927adfdf13458be9be22a -# FA Pro token to generate the vendored @rivet-gg/icons dist. Set it as a Railway -# build variable (passed via --build-arg locally). It is only referenced in this -# discarded build stage — the final caddy image never contains it. -ARG FONTAWESOME_PACKAGE_TOKEN -# The ARG is already in this RUN's environment, so the icons generate reads -# FONTAWESOME_PACKAGE_TOKEN directly — we don't echo it into the build log. -RUN git clone https://github.com/rivet-dev/docs-theme.git /theme \ - && git -C /theme checkout "$DOCS_THEME_SHA" \ - && pnpm -C /theme install \ - && pnpm -C /theme/packages/theme/vendor/icons run gen:manifest \ - && pnpm -C /theme/packages/theme/vendor/icons run gen:vendor \ - && pnpm -C /theme/packages/theme build - -# Copy the site source + the SDK source the typedoc step reads from ../packages. -COPY website/ ./ -COPY tsconfig.base.json /tsconfig.base.json -COPY packages/agentos /packages/agentos -# The docs embeds read example files from the embed root (/), -# resolved as /examples//. -COPY examples /examples - -# Point the theme deps at the clone (committed deps are workspace:* for local -# dev) and drop the injected meta, then install + build. -RUN node -e "const fs=require('fs'),p=require('./package.json'),d=p.dependencies;d['@rivet-dev/docs-theme']='file:/theme/packages/theme';d['@rivet-gg/components']='file:/theme/packages/theme/vendor/components';d['@rivet-gg/icons']='file:/theme/packages/theme/vendor/icons';delete p.dependenciesMeta;fs.writeFileSync('./package.json',JSON.stringify(p,null,2))" \ - && pnpm install \ - && pnpm build - -# Serve the static output. This is a static multi-page site (Astro/Starlight -# emits /index.html), NOT an SPA — so resolve each page's index.html and -# serve the real 404.html on a miss (no SPA fallback to the landing page). -FROM caddy:alpine -COPY --from=build /app/dist /srv -RUN cat > /etc/caddy/Caddyfile <<'EOF' -:80 { - root * /srv - encode gzip - - # Canonicalize directory requests to a trailing slash BEFORE try_files maps - # them to /index.html. Pages like the TypeDoc /api index reference - # their assets with relative URLs (e.g. "assets/style.css"). Without the - # trailing slash the browser's base URL stays "/api", so those relatives - # resolve to "/assets/style.css" at the site root and 404 (served as the - # unstyled 404.html). Redirecting "/api" -> "/api/" makes the base URL - # "/api/" so relative assets resolve to "/api/assets/...". The matcher only - # fires when the bare path is itself a real directory on disk, so genuine - # extension-less pages handled via {path}.html are unaffected. - @dir_no_slash { - not path */ - file { - try_files {path}/index.html - } - } - redir @dir_no_slash {path}/ 308 - - try_files {path} {path}/index.html {path}.html - file_server - handle_errors { - rewrite * /404.html - file_server - } -} -EOF -EXPOSE 80 diff --git a/website/astro.config.mjs b/website/astro.config.mjs deleted file mode 100644 index 2b598a254d..0000000000 --- a/website/astro.config.mjs +++ /dev/null @@ -1,104 +0,0 @@ -import { defineConfig } from "astro/config"; -import tailwind from "@astrojs/tailwind"; -import sitemap from "@astrojs/sitemap"; -import { docsTheme } from "@rivet-dev/docs-theme"; -import { siteConfig } from "./docs.config.mjs"; - -// https://astro.build/config -export default defineConfig({ - site: "https://agentos-sdk.dev", - output: "static", - integrations: [ - // The shared Rivet docs framework (copied 1:1 from rivet.dev, no Starlight). - // docsTheme() provides react + mdx + the remark/rehype/Shiki pipeline + - // route generation + the virtual config. docs.config.mjs maps agentOS's - // identity/nav/sitemap onto it. - ...docsTheme(siteConfig), - tailwind({ applyBaseStyles: false }), - sitemap(), - ], - vite: { - server: { - // Amp orbs can expose the dev server through an E2B portal hostname. - allowedHosts: [".e2b.app"], - }, - resolve: { - dedupe: ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime"], - }, - optimizeDeps: { - // Force EVERY React island dependency into one optimize pass at - // startup. Otherwise Vite discovers a dep lazily on first request - // (seen: "new dependencies optimized: @rivet-gg/components ... - // reloading"), reloads mid-render, and react-dom ends up referencing a - // React instance whose hook dispatcher was reset → "Invalid hook call" - // → islands never hydrate. The split is in the optimizer, not on disk. - // Ref: withastro/astro#16766. Keep this list in sync with the libs the - // theme + vendored components actually import in island code. - include: [ - "react", - "react-dom", - "react-dom/client", - "react/jsx-runtime", - "react/jsx-dev-runtime", - "@rivet-gg/components", - "@rivet-gg/icons", - "framer-motion", - "lucide-react", - "posthog-js", - "posthog-js/react", - "@sentry/react", - "@headlessui/react", - "@floating-ui/react", - "react-hook-form", - "react-markdown", - "react-day-picker", - "react-resizable-panels", - // CJS island deps that fail ESM interop unless pre-bundled (the - // actual hydration blocker — "does not provide an export"). They're - // imported from INSIDE the theme package, so use Vite's - // `linked-pkg > nested-dep` syntax to force them through optimize. - "typesense", - "use-sync-external-store", - "use-sync-external-store/shim", - "use-sync-external-store/with-selector", - "@rivet-dev/docs-theme > typesense", - "@rivet-dev/docs-theme > use-sync-external-store", - "@rivet-dev/docs-theme > use-sync-external-store/with-selector", - "@rivet-gg/components > use-sync-external-store", - "@rivet-gg/components > use-sync-external-store/with-selector", - "@radix-ui/react-accordion", - "@radix-ui/react-avatar", - "@radix-ui/react-checkbox", - "@radix-ui/react-context-menu", - "@radix-ui/react-dialog", - "@radix-ui/react-dropdown-menu", - "@radix-ui/react-label", - "@radix-ui/react-popover", - "@radix-ui/react-progress", - "@radix-ui/react-radio-group", - "@radix-ui/react-scroll-area", - "@radix-ui/react-select", - "@radix-ui/react-separator", - "@radix-ui/react-slider", - "@radix-ui/react-slot", - "@radix-ui/react-switch", - "@radix-ui/react-tabs", - "@radix-ui/react-toggle", - "@radix-ui/react-toggle-group", - "@radix-ui/react-tooltip", - "@radix-ui/react-visually-hidden", - ], - }, - ssr: { - // The theme/components ship .tsx, so they must be bundled for SSR — - // but keep React external so the bundled theme and react-dom/server - // share one instance (clears the SSR-side "Invalid hook call" noise). - external: ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime"], - noExternal: [ - "@rivet-dev/docs-theme", - "@rivet-gg/components", - "@rivet-gg/icons", - ], - }, - }, -}); diff --git a/website/docs.config.mjs b/website/docs.config.mjs deleted file mode 100644 index c5d72c020b..0000000000 --- a/website/docs.config.mjs +++ /dev/null @@ -1,310 +0,0 @@ -/** - * agentOS docs configuration for @rivet-dev/docs-theme (the de-Starlighted, - * rivet-1:1 framework). Maps agentOS identity/nav onto the theme's SiteConfig. - * - * `sitemap` is the docs navigation tree: SiteTab[] where each tab carries a - * sidebar tree (pages + collapsible sections). Routes are /docs/* (file paths - * under src/content/docs). Top-level sections are non-collapsible labels (rivet - * style); only nested page-groups collapse. Page items carry FontAwesome - * `IconDefinition`s for the sidebar icons. - * - * @type {import('@rivet-dev/docs-theme').SiteConfig} - */ -import { - faCircleInfo, - faForwardFast, - faLightbulb, - faScaleBalanced, - faRobot, - faToolbox, - faWrench, - faMessages, - faCheck, - faKey, - faDownload, - faFloppyDisk, - faTerminal, - faGlobe, - faCloud, - faClock, - faHardDrive, - faNodeJs, - faPython, - faGauge, - faTowerBroadcast, - faArrowsLeftRight, - faDiagramNext, - faWindowMaximize, - faMagnifyingGlass, -} from "@rivet-gg/icons"; - -export const siteConfig = { - product: "agentOS", - productLogo: "/images/agent-os/agentos-hero-logo.svg", - productHome: "/", - siteUrl: "https://agentos-sdk.dev", - favicon: { svg: "/favicon.svg" }, - repo: "rivet-dev/agentos", - editPath: "website/", - - // Cookbooks lives in the docs tab strip below, so do not duplicate it here. - topNav: [ - { label: "Documentation", href: "/docs", match: "/docs" }, - { label: "Use Cases", href: "/use-cases" }, - { label: "Registry", href: "/registry" }, - { label: "Deploy", href: "/docs/deployment", match: "/docs/deployment" }, - ], - tabs: [ - { label: "General", href: "/docs", match: "/docs" }, - { label: "Cookbooks", href: "/cookbooks", match: "/cookbooks" }, - ], - social: { discord: "https://rivet.dev/discord" }, - analytics: { posthogKey: "phc_6kfTNEAVw7rn1LA51cO3D69FefbKupSWFaM7OUgEpEo" }, - - // Hosted Typesense docs search (same cluster as rivet). The search-only key - // is safe to ship client-side; indexing uses the admin key (see scripts). - search: { - typesense: { - host: "3lsug6t152oxcjndp-1.a1.typesense.net", - searchApiKey: "o4qaOyinaSrfIVcxHwSjk0tby0pE14ry", - collectionName: "agentos-docs", - }, - }, - - sitemap: [ - { - title: "Documentation", - href: "/docs", - sidebar: [ - { - title: "General", - pages: [ - { title: "Quickstart", href: "/docs/quickstart", icon: faForwardFast }, - { title: "Crash Course", href: "/docs/crash-course", icon: faLightbulb }, - { title: "Inspector", href: "/docs/inspector", icon: faMagnifyingGlass }, - { title: "agentOS vs Sandbox", href: "/docs/versus-sandbox", icon: faScaleBalanced }, - ], - }, - { - title: "Agent", - pages: [ - { - title: "Agents", - collapsible: true, - icon: faRobot, - pages: [ - { title: "Pi", href: "/docs/agents/pi", icon: { src: "/images/registry/pi.svg" } }, - { title: "ClaudeCode", href: "/docs/agents/claude", badge: "Beta", icon: { src: "/images/registry/claude-code.svg" } }, - { title: "Codex", href: "/docs/agents/codex", badge: "Beta", icon: { src: "/images/registry/codex.svg" } }, - { title: "OpenCode", href: "/docs/agents/opencode", icon: { src: "/images/registry/opencode.svg" } }, - { title: "Custom Agents", href: "/docs/agents/custom", icon: faWrench }, - ], - }, - { - title: "Frameworks", - collapsible: true, - icon: faToolbox, - pages: [ - { - title: "Rivet", - href: "/docs/frameworks/rivet", - icon: { src: "/images/frameworks/rivet.svg" }, - }, - { - title: "Vercel Eve", - href: "/docs/frameworks/vercel-eve", - badge: "Beta", - icon: { src: "/images/frameworks/eve-icon.svg" }, - }, - { - title: "Flue", - href: "/docs/frameworks/flue", - badge: "Beta", - icon: { src: "/images/frameworks/flue.svg" }, - }, - ], - }, - { title: "Sessions & Transcripts", href: "/docs/sessions", icon: faMessages }, - { title: "Approvals", href: "/docs/approvals", icon: faCheck }, - { title: "Models & Credentials", href: "/docs/models-and-credentials", icon: faKey }, - ], - }, - { - title: "Execution", - pages: [ - { title: "Bash", href: "/docs/bash", icon: faTerminal }, - { title: "Node.js", href: "/docs/javascript", icon: faNodeJs }, - { title: "Python", href: "/docs/python", icon: faPython }, - ], - }, - { - title: "Orchestration", - pages: [ - { title: "AI-Generated Apps", href: "/docs/apps", badge: "Preview", icon: faCloud }, - { title: "Multiplayer", href: "/docs/multiplayer", icon: faTowerBroadcast }, - { title: "Workflows & Graphs", href: "/docs/workflows", icon: faDiagramNext }, - { title: "Crons & Loops", href: "/docs/cron", icon: faClock }, - { title: "Agent-to-Agent", href: "/docs/agent-to-agent", icon: faArrowsLeftRight }, - ], - }, - { - title: "Operating System", - pages: [ - { title: "Software", href: "/docs/software", icon: faDownload }, - { title: "Filesystem", href: "/docs/filesystem", icon: faFloppyDisk }, - { title: "Processes & Shells", href: "/docs/processes", icon: faTerminal }, - { title: "Networking & Previews", href: "/docs/networking", icon: faGlobe }, - { title: "Permissions", href: "/docs/permissions", icon: faKey }, - { title: "Resource Limits", href: "/docs/resource-limits", icon: faGauge }, - ], - }, - { - title: "Extensions", - pages: [ - { title: "Custom Bindings", href: "/docs/bindings", icon: faWrench }, - { title: "Browser Automation", href: "/docs/browser", badge: "Beta", icon: faWindowMaximize }, - { title: "External Sandboxes", href: "/docs/sandboxes", badge: "Beta", icon: faHardDrive }, - ], - }, - { - title: "Reference", - pages: [ - { title: "API Reference", href: "/api", external: true, target: "_blank" }, - { title: "Deploy", href: "/docs/deployment" }, - { title: "Authentication", href: "/docs/authentication" }, - { - title: "Custom Software", - collapsible: true, - pages: [ - { title: "Definition", href: "/docs/custom-software/definition" }, - { title: "Building Binaries", href: "/docs/custom-software/building-wasm" }, - { title: "Request Software", href: "https://github.com/rivet-dev/agentos/issues/new/choose", external: true, target: "_blank" }, - ], - }, - { - title: "Architecture", - collapsible: true, - pages: [ - { title: "Overview", href: "/docs/architecture" }, - { title: "Security Model", href: "/docs/security-model" }, - { title: "Limitations", href: "/docs/limitations" }, - { - title: "Advanced", - collapsible: true, - pages: [ - { title: "Agent Sessions", href: "/docs/architecture/agent-sessions" }, - { title: "Agent SDK Snapshots", href: "/docs/architecture/agent-sdk-snapshots" }, - { title: "Sessions & Persistence", href: "/docs/architecture/sessions-persistence" }, - { title: "Processes", href: "/docs/architecture/processes" }, - { title: "Filesystem", href: "/docs/architecture/filesystem" }, - { title: "Networking", href: "/docs/architecture/networking" }, - { title: "TLS & SSL", href: "/docs/architecture/tls-ssl" }, - { title: "JavaScript Executor & Reactor", href: "/docs/architecture/javascript-executor" }, - { title: "POSIX Syscalls", href: "/docs/architecture/posix-syscalls" }, - { title: "Packages & Command Resolution", href: "/docs/architecture/packages-and-command-resolution" }, - { title: "Compiler Toolchain", href: "/docs/architecture/compiler-toolchain" }, - { title: "Limits & Observability", href: "/docs/architecture/limits-and-observability" }, - { title: "System Prompt", href: "/docs/system-prompt" }, - { title: "Persistence & Sleep", href: "/docs/persistence" }, - ], - }, - ], - }, - { - title: "More", - collapsible: true, - pages: [ - { title: "Direct VM SDK", href: "/docs/core" }, - { title: "Debugging", href: "/docs/debugging" }, - { title: "Performance", href: "/docs/performance" }, - ], - }, - ], - }, - ], - }, - { - title: "Cookbooks", - href: "/cookbooks", - sidebar: [ - { title: "Overview", href: "/cookbooks", icon: faCircleInfo }, - { - title: "Quickstart", - pages: [ - { title: "Quickstart App", href: "/cookbooks/quickstart-app" }, - { title: "Crash Course", href: "/cookbooks/crash-course" }, - ], - }, - { - title: "Agents", - pages: [ - { title: "Pi Agent", href: "/cookbooks/pi" }, - { title: "Claude Agent", href: "/cookbooks/claude" }, - { title: "Codex Agent", href: "/cookbooks/codex" }, - { title: "OpenCode Agent", href: "/cookbooks/opencode" }, - { title: "Agent to Agent", href: "/cookbooks/agent-to-agent" }, - ], - }, - { - title: "Code Execution", - pages: [ - { title: "AI Agent Code Exec", href: "/cookbooks/js-ai-agent-code-exec" }, - { title: "Code Mode", href: "/cookbooks/js-code-mode" }, - { title: "Dev Servers", href: "/cookbooks/js-dev-servers" }, - { title: "Plugin Systems", href: "/cookbooks/js-plugin-systems" }, - ], - }, - { - title: "Filesystem", - pages: [{ title: "Filesystem", href: "/cookbooks/filesystem" }], - }, - { - title: "Processes & Shell", - pages: [ - { title: "Processes", href: "/cookbooks/processes" }, - { title: "Browser Terminal", href: "/cookbooks/browser-terminal" }, - ], - }, - { - title: "Networking", - pages: [{ title: "Networking", href: "/cookbooks/networking" }], - }, - { - title: "Sessions & Permissions", - pages: [ - { title: "Sessions", href: "/cookbooks/sessions" }, - { title: "Permissions", href: "/cookbooks/permissions" }, - { title: "Approvals", href: "/cookbooks/approvals" }, - { title: "Authentication", href: "/cookbooks/authentication" }, - { title: "LLM Credentials", href: "/cookbooks/llm-credentials" }, - { title: "Multiplayer", href: "/cookbooks/multiplayer" }, - { title: "Persistence", href: "/cookbooks/persistence" }, - ], - }, - { - title: "Orchestration", - pages: [ - { title: "Cron", href: "/cookbooks/cron" }, - { title: "Workflows", href: "/cookbooks/workflows" }, - ], - }, - { - title: "Integrations", - pages: [{ title: "Vercel Eve", href: "/cookbooks/eve" }], - }, - { - title: "Reference", - pages: [ - { title: "Core", href: "/cookbooks/core" }, - { title: "Software", href: "/cookbooks/software" }, - { title: "Bindings", href: "/cookbooks/bindings" }, - { title: "Resource Limits", href: "/cookbooks/resource-limits" }, - { title: "Sandbox", href: "/cookbooks/sandbox" }, - ], - }, - ], - }, - ], -}; - -export default siteConfig; diff --git a/website/package.json b/website/package.json deleted file mode 100644 index 07e6853f0b..0000000000 --- a/website/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@rivet-dev/agentos-website", - "private": true, - "version": "0.0.1", - "license": "Apache-2.0", - "type": "module", - "scripts": { - "dev": "node scripts/gen-registry.mjs && astro dev", - "start": "node scripts/gen-registry.mjs && astro dev", - "docs:gen:ts": "typedoc", - "gen:registry": "node scripts/gen-registry.mjs", - "check-types": "astro check", - "build": "node scripts/gen-registry.mjs && pnpm run docs:gen:ts && astro build", - "preview": "astro preview", - "astro": "astro", - "docs:index": "node --input-type=module -e \"import('@rivet-dev/docs-theme/scripts/index-docs').then(m => m.indexDocs())\"" - }, - "dependencies": { - "@astrojs/react": "^4.2.0", - "@astrojs/sitemap": "^3.2.0", - "@astrojs/tailwind": "^6.0.0", - "@rivet-dev/docs-theme": "workspace:*", - "@rivet-gg/components": "workspace:*", - "@rivet-gg/icons": "workspace:*", - "astro": "^5.18.2", - "framer-motion": "^12.0.0", - "lucide-react": "^0.469.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "sharp": "^0.33.5", - "tailwindcss": "^3.4.0" - }, - "devDependencies": { - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "typedoc": "^0.28.19", - "typescript": "^5.7.0", - "vite": "^6.4.1" - }, - "dependenciesMeta": { - "@rivet-dev/docs-theme": { - "injected": true - }, - "@rivet-gg/components": { - "injected": true - }, - "@rivet-gg/icons": { - "injected": true - } - } -} diff --git a/website/public/backgroundsecure.png b/website/public/backgroundsecure.png deleted file mode 100644 index 0de556070e..0000000000 Binary files a/website/public/backgroundsecure.png and /dev/null differ diff --git a/website/public/chrome-btn-hover.png b/website/public/chrome-btn-hover.png deleted file mode 100644 index e868c91fc0..0000000000 Binary files a/website/public/chrome-btn-hover.png and /dev/null differ diff --git a/website/public/chrome-btn.png b/website/public/chrome-btn.png deleted file mode 100644 index bcd8de6ce2..0000000000 Binary files a/website/public/chrome-btn.png and /dev/null differ diff --git a/website/public/chrome-btn.svg b/website/public/chrome-btn.svg deleted file mode 100644 index e6315ac56d..0000000000 --- a/website/public/chrome-btn.svg +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/website/public/chrome/01_base_fill.png b/website/public/chrome/01_base_fill.png deleted file mode 100644 index 0dc0b7eb75..0000000000 Binary files a/website/public/chrome/01_base_fill.png and /dev/null differ diff --git a/website/public/chrome/02_rim_outer.png b/website/public/chrome/02_rim_outer.png deleted file mode 100644 index 55561b0944..0000000000 Binary files a/website/public/chrome/02_rim_outer.png and /dev/null differ diff --git a/website/public/chrome/03_inner_bevel.png b/website/public/chrome/03_inner_bevel.png deleted file mode 100644 index 10866ffe9c..0000000000 Binary files a/website/public/chrome/03_inner_bevel.png and /dev/null differ diff --git a/website/public/chrome/04_highlight_top.png b/website/public/chrome/04_highlight_top.png deleted file mode 100644 index b9256755a2..0000000000 Binary files a/website/public/chrome/04_highlight_top.png and /dev/null differ diff --git a/website/public/chrome/05_reflection_bottom.png b/website/public/chrome/05_reflection_bottom.png deleted file mode 100644 index fa6e514c65..0000000000 Binary files a/website/public/chrome/05_reflection_bottom.png and /dev/null differ diff --git a/website/public/chrome/06_side_reflections.png b/website/public/chrome/06_side_reflections.png deleted file mode 100644 index 90b483acac..0000000000 Binary files a/website/public/chrome/06_side_reflections.png and /dev/null differ diff --git a/website/public/chrome/07_specular_sparks.png b/website/public/chrome/07_specular_sparks.png deleted file mode 100644 index 94b1d6c914..0000000000 Binary files a/website/public/chrome/07_specular_sparks.png and /dev/null differ diff --git a/website/public/chrome/08_hover_glow.png b/website/public/chrome/08_hover_glow.png deleted file mode 100644 index 14a6748b45..0000000000 Binary files a/website/public/chrome/08_hover_glow.png and /dev/null differ diff --git a/website/public/chrome/09_hover_sheen.png b/website/public/chrome/09_hover_sheen.png deleted file mode 100644 index 648029d3d9..0000000000 Binary files a/website/public/chrome/09_hover_sheen.png and /dev/null differ diff --git a/website/public/chrome/11_shadow_inner.png b/website/public/chrome/11_shadow_inner.png deleted file mode 100644 index 8c873423cd..0000000000 Binary files a/website/public/chrome/11_shadow_inner.png and /dev/null differ diff --git a/website/public/docs/docs.md b/website/public/docs/docs.md deleted file mode 100644 index b3db53ad49..0000000000 --- a/website/public/docs/docs.md +++ /dev/null @@ -1,7 +0,0 @@ -# Introduction - -Run coding agents inside isolated VMs with full filesystem, process, and network control. - -agentOS runs coding agents inside isolated VMs with full filesystem, process, and -network control — a lightweight VM in your own process with bindings, permissions, -and orchestration built in. \ No newline at end of file diff --git a/website/public/docs/docs/agent-to-agent.md b/website/public/docs/docs/agent-to-agent.md deleted file mode 100644 index 5557b173d0..0000000000 --- a/website/public/docs/docs/agent-to-agent.md +++ /dev/null @@ -1,30 +0,0 @@ -# Agent-to-Agent Communication - -Use bindings to let agents communicate with each other. - -Agents communicate through [bindings](/docs/bindings). You define a bindings group that lets one agent send work to another, and the agent calls it like any other CLI command. - -## Example: code writer + reviewer - -This example gives the writer agent a `review` binding. The writer sends the file's full contents (the VMs share no filesystem), and the binding writes them into a separate reviewer VM and sends a review prompt back through the reviewer. - -The writer agent sees the review binding as a CLI command. Because the VMs share no filesystem, it sends the full file contents, not a path: - -```bash -agentos-review submit --code "$(cat api.ts)" -``` - -The binding writes the contents into the reviewer's VM, prompts the reviewer, and returns the review to the writer as JSON. - -## Why bindings? - -Bindings are the natural communication layer between agents because: - -- **The agent doesn't need to know about other agents.** It just calls a binding. You can swap the implementation without changing the agent's behavior. -- **No credentials in the VM.** The binding executes on the server, so it can access other agents directly without exposing connection details. -- **Composable.** Chain any number of agents by adding more bindings. Each binding is a self-contained bridge to another agent. - -## Recommendations - -- Each agent has its own isolated VM and filesystem (they share no filesystem). Pass file contents through the binding input, then use `writeFile` in the binding to land them in the other VM. -- Use [Workflows](/docs/workflows) to make multi-agent pipelines durable across restarts. \ No newline at end of file diff --git a/website/public/docs/docs/agents/claude.md b/website/public/docs/docs/agents/claude.md deleted file mode 100644 index 7a9a65863c..0000000000 --- a/website/public/docs/docs/agents/claude.md +++ /dev/null @@ -1,34 +0,0 @@ -# Claude Code - -Run the Claude Code agent inside a VM with skills, MCP servers, and custom configuration. - -## Quick start - -Read [Sessions](/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. - -## Model & credentials - -Set the relevant variable(s) on the session's `env`, sourced from your server's environment: - -- `ANTHROPIC_API_KEY` — Anthropic API key (direct API). -- `ANTHROPIC_AUTH_TOKEN` — bearer token for proxy / OAuth auth. -- `ANTHROPIC_BASE_URL` — route through a gateway or proxy endpoint. -- `ANTHROPIC_MODEL` — override the default model. -- `CLAUDE_CODE_USE_BEDROCK=1` — use Amazon Bedrock (auth via the AWS credential chain: `AWS_REGION`, `AWS_PROFILE`, …). -- `CLAUDE_CODE_USE_VERTEX=1` — use Google Vertex AI (auth via Google Cloud credentials). - -See [Models & Credentials](/docs/models-and-credentials), and Claude Code's [environment variables](https://code.claude.com/docs/en/env-vars) for the full list. - -## Skills - -Claude Code discovers [agent skills](https://docs.claude.com/en/docs/claude-code/skills) from `SKILL.md` files under its skills directory. Write the skill into the VM before creating a session and Claude Code loads it automatically. - -## MCP servers - -Expose extra tools to the agent by passing `mcpServers` to `openSession`. Both local child-process servers and remote URLs are supported. - -**Pre-install `npx`-launched servers.** A local server started with `npx -y …` writes install progress to **stdout** on its first run, which corrupts the MCP stdio handshake (you'll see `Connection closed`). Pre-install it in the VM so `npx` is silent — `await agent.process.exec("npm install -g @modelcontextprotocol/server-filesystem")` before the session — or pin the package and point `command` at the installed binary. - -## Customizing the agent - -Claude Code is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked build as a new agent, see [Custom Agents](/docs/agents/custom). \ No newline at end of file diff --git a/website/public/docs/docs/agents/codex.md b/website/public/docs/docs/agents/codex.md deleted file mode 100644 index baeacc7081..0000000000 --- a/website/public/docs/docs/agents/codex.md +++ /dev/null @@ -1,31 +0,0 @@ -# Codex - -Run the Codex coding agent inside a VM with skills, MCP servers, and custom configuration. - -## Quick start - -Read [Sessions](/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. - -## Model & credentials - -Set the relevant variable(s) on the session's `env`, sourced from your server's environment: - -- `OPENAI_API_KEY` — OpenAI API key (built-in `openai` provider). -- `OPENAI_BASE_URL` — route through a gateway or OpenAI-compatible endpoint. -- Custom providers — defined in `~/.codex/config.toml`; each provider's `env_key` names the variable Codex reads for its key (e.g. `AZURE_OPENAI_API_KEY`, `MISTRAL_API_KEY`). - -See [Models & Credentials](/docs/models-and-credentials), and Codex's [config reference](https://developers.openai.com/codex/config-reference) for details. - -## Skills - -Codex discovers `SKILL.md` files from its skills directory. Write the skill into the VM before creating a session and Codex loads it automatically. - -## MCP servers - -Expose extra tools to the agent by passing `mcpServers` to `openSession`. Both local child-process servers and remote URLs are supported. - -**Pre-install `npx`-launched servers.** A local server started with `npx -y …` writes install progress to **stdout** on its first run, which corrupts the MCP stdio handshake (you'll see `Connection closed`). Pre-install it in the VM so `npx` is silent — `await agent.process.exec("npm install -g @modelcontextprotocol/server-filesystem")` before the session — or pin the package and point `command` at the installed binary. - -## Customizing the agent - -Codex is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked build as a new agent, see [Custom Agents](/docs/agents/custom). \ No newline at end of file diff --git a/website/public/docs/docs/agents/custom.md b/website/public/docs/docs/agents/custom.md deleted file mode 100644 index 845b535260..0000000000 --- a/website/public/docs/docs/agents/custom.md +++ /dev/null @@ -1,69 +0,0 @@ -# Custom Agents - -Bring your own coding agent to agentOS by speaking the Agent Client Protocol (ACP) inside the VM. - -A custom agent is a program that runs **inside the VM** to drive a coding agent. AgentOS spawns it when you call `openSession({ sessionId, agent })` and talks to it over the Agent Client Protocol. You ship it as a software package, exactly like the built-in agents. - -## Agent Client Protocol (ACP) - -agentOS speaks the [Agent Client Protocol (ACP)](https://agentclientprotocol.com) to every agent: JSON-RPC over stdio. The agent reads protocol messages on **stdin** and writes them on **stdout**, so stdout is reserved for ACP and **stderr is used for logs**. Your program only needs to speak ACP; how it runs the underlying model is up to you. See the [ACP documentation](https://agentclientprotocol.com) for the full protocol. - -## Two ways to build an agent - -There are two shapes, depending on whether the agent runs in the ACP process or in its own. - -### Single process (embedded) - -The ACP adapter **embeds the agent SDK** and runs it in the same process. One process inside the VM, lower memory footprint. - - Host - ACP - VM - ACP adapter + - agent (embedded) - -For example, an adapter to run **OpenCode**, which speaks ACP natively. One package is both the ACP process and the agent, so there's no separate adapter and nothing else is spawned. - -### ACP adapter (separate agent) - -The ACP adapter is a thin **bridge** that spawns the real agent as its **own process** (a CLI or SDK) and translates between it and ACP. Full agent feature set, higher memory. - - Host - ACP - VM - ACP adapter - spawns - Agent process - (CLI / SDK) - -For example, an adapter to run **Pi**: the `pi` CLI doesn't speak ACP, so `pi-acp` speaks ACP and spawns the CLI as a separate process. The packaged agent bundles both — its `agentos-package.json` names `pi-acp` as the `acpEntrypoint` and points it at the `pi` CLI via `agent.env`. - -## Use your agent - -Register the package on the server with `software`. Sessions are then created from the client by `id`, exactly like any built-in agent. - -```ts title="server.ts" -import { agentOS, setup, defineSoftware } from "@rivet-dev/agentos"; - -const myAgent = defineSoftware({ - packagePath, // the packed agent .aospkg; its embedded manifest carries the agent block -}); - -const vm = agentOS({ software: [myAgent] }); - -export const registry = setup({ use: { vm } }); -registry.start(); -``` - -See [Sessions](/docs/sessions) for creating and driving sessions. Package your adapter with `agentos-toolchain pack --agent my-agent-acp` so its dependencies are bundled into the self-contained package directory and the `agent` block (naming the `bin/` ACP entrypoint) is written into the package's `agentos-package.json`, rather than shipping it as a loose file. - -All built-in agents are defined exactly this way. Browse them for reference on [GitHub](https://github.com/rivet-dev/agentos/tree/main/software). - -## Read more - -- [Defining software packages](/docs/custom-software/definition): the full descriptor reference, including the `agentos-package.json` schema and every `agent` field (`acpEntrypoint`, `env`, `launchArgs`, `snapshot`). -- [Building binaries](/docs/custom-software/building-wasm): compile WASM command binaries and use the registry. - -## Debugging - -When a custom agent exits mid-turn or a tool call fails, capture the agent's stderr with the `onAgentStderr` hook on `AgentOs.create()`. The agent uses stdout for ACP, so stderr carries its logs and crash output. See [Debugging](/docs/debugging) for that hook and the runtime (sidecar) logs. \ No newline at end of file diff --git a/website/public/docs/docs/agents/opencode.md b/website/public/docs/docs/agents/opencode.md deleted file mode 100644 index cb8b9576fa..0000000000 --- a/website/public/docs/docs/agents/opencode.md +++ /dev/null @@ -1,63 +0,0 @@ -# OpenCode - -Run the OpenCode coding agent inside a VM with skills, MCP servers, and custom configuration. - -## Quick start - -Read [Sessions](/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. - -## Model & credentials - -OpenCode auto-detects a provider when its key is present on the session's `env`, sourced from your server's environment. Common variables: - -- `ANTHROPIC_API_KEY` — Anthropic (Claude), the default. -- `OPENAI_API_KEY` — OpenAI. -- `OPENROUTER_API_KEY` — OpenRouter. -- `GEMINI_API_KEY` — Google Gemini. -- `GROQ_API_KEY` — Groq. -- …plus Amazon Bedrock, Azure, Google Vertex, and 70+ providers via [models.dev](https://models.dev). - -See [Models & Credentials](/docs/models-and-credentials), and OpenCode's [providers docs](https://opencode.ai/docs/providers/) for the full list. - -## Model configuration - -To pin a specific model — or point a provider at a custom endpoint — write an OpenCode config file into the VM before creating the session. OpenCode reads `/.config/opencode/opencode.json` (the agent's `HOME` is `/home/agentos` by default). - -Two settings will silently produce an **empty response** if wrong: -- The Anthropic provider **`baseURL` must end in `/v1`** (`https://api.anthropic.com/v1`). Without `/v1`, OpenCode calls `…/messages` and Anthropic returns `404 Not Found`. -- The **`model` must be a current model id.** A retired id returns a `404 not_found_error` and the turn ends with zero output. - -```ts -// Write the config before creating the session -await agent.filesystem.mkdir("/home/agentos/.config/opencode", { recursive: true }); -await agent.filesystem.writeFile( - "/home/agentos/.config/opencode/opencode.json", - JSON.stringify({ - $schema: "https://opencode.ai/config.json", - model: "anthropic/claude-haiku-4-5-20251001", // use a current model id - provider: { - // The Anthropic baseURL MUST include /v1, or requests 404. - anthropic: { options: { baseURL: "https://api.anthropic.com/v1" } }, - }, - }), -); - -await agent.sessions.open({ - agent: "opencode", - env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! }, -}); -``` - -## Skills - -OpenCode discovers `SKILL.md` files from its skills directory. Write the skill into the VM before creating a session and OpenCode loads it automatically. - -## MCP servers - -Expose extra tools to the agent by passing `mcpServers` to `openSession`. Both local child-process servers and remote URLs are supported. - -**Pre-install `npx`-launched servers.** A local server started with `npx -y …` writes install progress to **stdout** on its first run, which corrupts the MCP stdio handshake (you'll see `Connection closed`). Pre-install it in the VM so `npx` is silent — `await agent.process.exec("npm install -g @modelcontextprotocol/server-filesystem")` before the session — or pin the package and point `command` at the installed binary. - -## Customizing the agent - -OpenCode is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked build as a new agent, see [Custom Agents](/docs/agents/custom). \ No newline at end of file diff --git a/website/public/docs/docs/agents/pi.md b/website/public/docs/docs/agents/pi.md deleted file mode 100644 index 4334b9d1e2..0000000000 --- a/website/public/docs/docs/agents/pi.md +++ /dev/null @@ -1,43 +0,0 @@ -# Pi - -Run the Pi coding agent inside a VM with extensions and custom configuration. - -## Quick start - -Read [Sessions](/docs/sessions) first for session options, streaming events, prompts, and lifecycle management. - -## Model & credentials - -Set the relevant variable on the session's `env`, sourced from your server's environment: - -- `ANTHROPIC_API_KEY` — Anthropic (Claude), the default. -- Other providers — use the provider-named key (e.g. `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENROUTER_API_KEY`). - -See [Models & Credentials](/docs/models-and-credentials), and Pi's [providers docs](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/providers.md) for the full list. - -## Skills - -Pi discovers `SKILL.md` files from its skills directory. Write the skill into the VM before creating a session and Pi loads it automatically. - -## MCP servers - -Expose extra tools to the agent by passing `mcpServers` to `openSession`. Both local child-process servers and remote URLs are supported. - -**Pre-install `npx`-launched servers.** A local server started with `npx -y …` writes install progress to **stdout** on its first run, which corrupts the MCP stdio handshake (you'll see `Connection closed`). Pre-install it in the VM so `npx` is silent — `await agent.process.exec("npm install -g @modelcontextprotocol/server-filesystem")` before the session — or pin the package and point `command` at the installed binary. - -## Extensions - -Pi supports [extensions](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent/examples/extensions) that let you register custom tools, modify the system prompt, and hook into agent lifecycle events. Write a `.js` file into the VM's extensions directory before creating a session and Pi discovers it automatically. - -Pi scans two directories for `.js` extension files: - -| Directory | Scope | -|-----------|-------| -| `~/.pi/agent/extensions/` | Global — applies to all Pi sessions | -| `/.pi/extensions/` | Project — applies only when cwd matches | - -See the [Pi extension documentation](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent/examples/extensions) for the full extension API. - -## Customizing the agent - -Pi is a built-in agent, but it's just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked Pi build as a new agent, see [Custom Agents](/docs/agents/custom). \ No newline at end of file diff --git a/website/public/docs/docs/approvals.md b/website/public/docs/docs/approvals.md deleted file mode 100644 index 3a998af871..0000000000 --- a/website/public/docs/docs/approvals.md +++ /dev/null @@ -1,33 +0,0 @@ -# Approvals - -Handle native ACP permission options with durable AgentOS correlation. - -Set a session's immutable `permissionPolicy` when calling `openSession`: - -- `reject_all` prefers a native `reject_once` option, then `reject_always`, and fails with `permission_policy_unsatisfied` when neither exists. -- `allow_all` (the default) prefers `allow_once`, then `allow_always`. -- `ask` durably records the exact ACP `RequestPermissionRequest` in the ordinary sequenced session-event stream. - -This controls how AgentOS answers an adapter's native ACP permission request. It does not grant VM filesystem or network permissions, change which tools the adapter exposes, or become ACP adapter configuration. - -Subscribing to session events does not enable interactive approval. You must set `permissionPolicy: "ask"` in `openSession`; if it is omitted, the default `allow_all` policy resolves requests automatically and no `permission_request` event is emitted or persisted. - -## Human in the loop - -With `ask`, respond using the AgentOS `requestId` plus one of the exact `optionId` values supplied by the adapter. Do not translate options into AgentOS-specific `once`/`always` strings. - -The `permission_request` session-event variant contains: - -- `sessionId`: stable public AgentOS session ID from the durable event envelope. -- `requestId`: globally unique AgentOS correlation ID; the adapter JSON-RPC ID is private. -- `toolCall`, `options`, and optional `_meta`: exact native ACP request fields exposed directly, without a nested `request` object. - -`respondPermission` requires an explicit `sessionId` and returns `accepted` or `not_pending` with a specific terminal reason. The first valid response wins atomically. Invalid options fail with `invalid_permission_option` and list the offered IDs. `accepted` means the decision reached the active ACP waiter; it does not mean the tool operation succeeded. - -Permission requests have no sidecar expiry. They remain pending until answered or terminated by prompt cancellation, adapter exit, session deletion, or VM shutdown. RivetKit's actor-wide safety bound defaults to about 24.8 days rather than the old 15-minute action timeout. Both the request and its accepted response are durable history entries, so reconnecting consumers subscribe, read history after their last sequence, and deduplicate by `(sessionId, sequence)`. - -## Automatic policy - -For a fully automated session, omit `permissionPolicy` or choose `allow_all` explicitly. No permission event or client round-trip is required. - -For unattended fail-closed work, choose `reject_all` explicitly. ACP approval is advisory; VM filesystem, network, and process permissions remain the security boundary. Automatically handled requests are neither emitted nor persisted. \ No newline at end of file diff --git a/website/public/docs/docs/apps.md b/website/public/docs/docs/apps.md deleted file mode 100644 index 70c93933b7..0000000000 --- a/website/public/docs/docs/apps.md +++ /dev/null @@ -1,219 +0,0 @@ -# agentOS Apps - -Deploy user-generated applications in agentOS VMs. - -agentOS Apps runs user-generated HTTP applications on Rivet. Apps can add -durable SQLite state, workflows, multiplayer and realtime state, queues, and -cron jobs. - -agentOS Apps is in preview and its API is subject to change. - -## Architecture - -**agentOS Apps is a library, not a hosted AI-generated app deployment -platform.** Unlike managed platforms, you can deploy it anywhere and customize -the server, routing, authentication, and deployment flow. - -Requests reach your Hono server, where `appsRouter` routes them to a prewarmed -agentOS VM serving the generated application. Rivet handles request routing and -orchestrates the pool of prewarmed VMs. - - OS - - Request - Agent · Browser · API - - Your Hono server - appsRouter - route the request - - Rivet - - Prewarmed VM - AI-generated app - serves the response - -## Quickstart - -[View the complete Quickstart example on GitHub](https://github.com/rivet-dev/agentos/tree/main/examples/apps-hello-world). - -```sh -npm add @rivet-dev/agentos @rivet-dev/agentos-apps -npm add @hono/node-server hono -npm add --save-dev tsx -npm pkg set type=module -``` - -Setup the HTTP server that will serve requests for AI-generated apps. Also set -up the actors that power the deployments. - -Run the server: - -```sh -npx tsx src/server.ts -``` - -Pass generated files directly to `deployApp()`. This can be called by an agent, -an upload endpoint, or any other part of your system: - -```sh -npx tsx src/deploy.ts -``` - -Open `http://localhost:3000/apps/hello-world/`. Pass this URL to agents, -frontends, or any other part of your system that needs to visit the deployment. - -Deploy the host server to any supported target: - -See [Deployment](/docs/deployment) for managed and self-hosted options. - -## Deploy App Reference - -Deploy a directory: - -```ts -await deployApp({ - appId: "hello-world", - source: new URL("../fixtures/app/", import.meta.url), -}); -``` - -Or deploy generated files: - -```ts -await deployApp({ - appId: "generated-app", - files: { - "index.html": "

Hello

", - }, -}); -``` - -### TypeScript repair - -`deployApp()` returns build diagnostics when generated TypeScript does not -compile. An agent can use those diagnostics to repair the files and call -`deployApp()` again: - -```ts -for (let attempt = 0; attempt < 3; attempt++) { - try { - await deployApp({ appId: "generated-app", files }); - break; - } catch (error) { - if (attempt === 2) throw error; - files = await repairWithAgent(files, String(error)); - } -} -``` - -A failed build does not replace the currently active release. See the -[AI App Builder example](https://github.com/rivet-dev/agentos/tree/main/examples/apps-ai-builder). - -`appId` must contain 1–63 lowercase letters, numbers, or hyphens. Pass exactly -one of `source` or `files`. - -### Configuration - -```ts -await deployApp({ - appId: "my-app", - source, - regions: ["atl", "fra"], - createNamespace: true, - scaling: { - minReplicas: 0, - maxReplicas: 128, - targetConcurrency: 8, - }, -}); -``` - -| Option | Default | -| --- | --- | -| `regions` | Current Rivet region | -| `createNamespace` | `false` | -| `scaling.minReplicas` | `0` | -| `scaling.maxReplicas` | `128` | -| `scaling.targetConcurrency` | `8` | - -By default, apps use the namespace configured on the ordinary Rivet client. -Enable `createNamespace` only when the app needs its own namespace; it requires -Rivet namespace list and create permissions. - -## Route requests - -Mount all deployed apps: - -```ts -server.route("/apps", appsRouter); -``` - -This routes `/apps/:appId` and `/apps/:appId/*`. To use an explicit RivetKit -client: - -```ts -import { createAppsRouter } from "@rivet-dev/agentos-apps/advanced"; - -server.route("/apps", createAppsRouter({ client })); -``` - -## Add Capabilities to Apps - -Agents can generate more than pages and REST APIs. These examples show apps -with durable SQLite data, workflows, multiplayer state, queues, and scheduled -jobs. The server snippets represent AI-generated app code; the client snippets -show how another part of your system connects to it. - -### SQLite - -Example AI-generated app code that stores durable data in an actor-owned SQLite -database. [View the complete SQLite example](https://github.com/rivet-dev/agentos/tree/main/examples/apps-sqlite). - -### Workflows - -Example AI-generated app code that runs durable multi-step jobs that can sleep -and resume. [View the complete workflows example](https://github.com/rivet-dev/agentos/tree/main/examples/apps-workflows). - -### Multiplayer - -Example AI-generated app code that shares realtime state between clients. -[View the complete multiplayer example](https://github.com/rivet-dev/agentos/tree/main/examples/apps-multiplayer). - -### Queues - -AI-generated apps can use actor queues for durable background work and ordered -processing. - -### Cron jobs - -AI-generated apps can schedule recurring work from an actor. See -[Cron Jobs](/docs/cron). - -These capabilities use RivetKit and its ordinary DirectActor client. agentOS -Apps does not wrap the client. - -## Build Apps with AI - -Give an agent the app requirements, let it generate the project files, and pass -those files to `deployApp()`. If the build returns TypeScript diagnostics, give -them back to the agent and deploy its repaired files again. - -[View the complete AI App Builder example](https://github.com/rivet-dev/agentos/tree/main/examples/apps-ai-builder). - -## Authentication - -Use normal Hono middleware to authenticate requests before they reach deployed -apps: - -```ts -server.use("/apps/*", authMiddleware); -server.route("/apps", appsRouter); -``` - -## Planned Improvements - -- Automatically include agent skills based on the - [Rivet Cookbooks](https://rivet.dev/cookbook/) for better app generation. -- Billing API for tracking and charging for app usage. -- Built-in error reporting for generated apps. \ No newline at end of file diff --git a/website/public/docs/docs/architecture.md b/website/public/docs/docs/architecture.md deleted file mode 100644 index ca952ffc0e..0000000000 --- a/website/public/docs/docs/architecture.md +++ /dev/null @@ -1,228 +0,0 @@ -# Overview - -A high-level tour of how agentOS works: the client / server / VM picture, the anatomy of a Linux VM (kernel + executor), agents and sessions, and the Rivet Actor orchestration underneath. - -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. - - OS - Client - JS · Browser · Backend - Server - OS - = an isolated VM - -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](/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. - - The VM - - Kernel - trusted core, every operation goes through here - virtual filesystem - process table - socket table - pipes / PTYs - DNS - permission policy · network allowlist · resource limits - - syscalls / replies - - Executor - untrusted, runs guest code, holds no capabilities - guest JavaScript (native V8) - WASM - shell · coreutils · npm packages · native binaries - -### Kernel: the trusted core - - guest request - Kernel - filesystem - processes - network & DNS - policy & limits - -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 - - Executor - untrusted · no capabilities - JS (V8) - WASM - nativebinaries - syscall - reply - Kernel - -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](/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](/docs/architecture/posix-syscalls) and the [Compiler Toolchain](/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 - - exec() / run() - spawn / shell - process table - virtual · per-VM - pipes & PTYs - -- **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](/docs/architecture/processes) for the internals. - -### Virtual filesystem - - overlay (guest writes) - root layer (snapshot) - host dir mount - S3 mount - cloud store - mount points grafted onto guest paths - -- **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](/docs/architecture/filesystem) for the internals. - -### Networking - - fetch() - node:http - node:net - WASM sockets - socket table - kernel-owned - egress allowlist - -- **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](/docs/architecture/networking) for the internals. - -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](/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. - - Client - your app - - prompt - events - - The VM - Agent session - long-lived agent process - - Filesystem - SQLite over UDS - -### 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](/docs/system-prompt). -- See [Agent Sessions](/docs/architecture/agent-sessions) for the internals. - -### Permissions & approvals - -- **Two layers, different jobs.** The lower-level [permission policy](/docs/permissions) is enforced by the kernel on every guest syscall (nothing is allowed until you opt in). On top of that, [approvals](/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](/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](/docs/inspector) tabs in the Rivet dashboard, so every actor comes with a live view of its transcript, filesystem, and processes. - - Rivet Actor - durable, addressable server object - - agentOS VM - the virtual Linux VM - - Cron - Workflows - Persistence · sleep / wake - Durablestate - -### 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](/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](/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](/docs/persistence). - -## Going deeper - -This page is the map. Each subsystem has its own detailed page in the Advanced architecture section: - -- **[Agent Sessions](/docs/architecture/agent-sessions)**: how a session is bound to a VM, and how prompts and events flow end to end. -- **[Processes](/docs/architecture/processes)**: the virtual process table, `exec()` / `run()`, child processes, and PTYs. -- **[Filesystem](/docs/architecture/filesystem)**: the per-VM virtual filesystem, overlays, and host-backed mounts. -- **[Networking](/docs/architecture/networking)**: the virtual socket table, DNS, the allowlist, and guest `fetch()`. -- **[JavaScript Executor & Socket Reactor](/docs/architecture/javascript-executor)**: how the shared Tokio runtime, V8 executor threads, coalesced readiness, bounded channels, and Node stream backpressure fit together. -- **[POSIX Syscalls](/docs/architecture/posix-syscalls)**: how WebAssembly guests behave like normal POSIX programs on top of the kernel. -- **[Compiler Toolchain](/docs/architecture/compiler-toolchain)**: how the shell and coreutils are compiled to WebAssembly and mounted into the VM. -- **[System Prompt](/docs/system-prompt)**: the context agentOS injects into every agent session. -- **[Persistence & Sleep](/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](/docs/security-model). \ No newline at end of file diff --git a/website/public/docs/docs/architecture/agent-sdk-snapshots.md b/website/public/docs/docs/architecture/agent-sdk-snapshots.md deleted file mode 100644 index 0cd26fcb8f..0000000000 --- a/website/public/docs/docs/architecture/agent-sdk-snapshots.md +++ /dev/null @@ -1,73 +0,0 @@ -# Agent SDK Snapshots - -How an agent's SDK is evaluated once per sidecar into a V8 heap snapshot and reused across sessions instead of re-imported on every openSession: the bundle, the userland snapshot, the process-wide cache, pre-warm, per-session restore, isolation, and the snapshot-safety rules an SDK must follow. - -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. - -This page is an internals deep-dive on **agent SDK snapshotting** — an optional optimization that loads an agent's SDK *once per sidecar* and reuses it for every session, instead of re-evaluating the whole SDK module graph on each `openSession`. For the agent-author view (how to opt in and the rules your SDK must follow), see [Software Definition → SDK snapshotting & snapshot-safety](/docs/custom-software/definition). For how sessions work in general, see [Agent Sessions](/docs/architecture/agent-sessions). - -## The problem: per-session SDK re-evaluation - -When a session starts, its agent adapter runs inside a fresh [V8 isolate](/docs/architecture/agent-sessions) and imports the agent SDK (for Pi, `@mariozechner/pi-coding-agent`). Importing a real-world SDK means resolving, loading, compiling, and **evaluating** a large module graph — hundreds of modules running their top-level initialization. That evaluation dominates session-creation latency, and because every session gets a fresh isolate, it is paid *again on every `openSession`*. - -The work is identical every time: the same modules, evaluated to the same post-init heap, only to be thrown away when the session ends. Snapshotting captures that post-init heap once and stamps it into every new isolate. - -## How V8 heap snapshots work here - -agentOS already boots every guest isolate from a **V8 startup snapshot** of the runtime bridge (the polyfill layer that provides `fetch`, node builtins, the kernel-backed module loader, etc.). A startup snapshot is a serialized image of a V8 heap *after* some code has run; restoring it into a fresh isolate reproduces that heap by deserialization rather than re-execution, and each restore produces an independent context. - -Agent SDK snapshotting extends that same mechanism: it evaluates the agent SDK **into the same snapshot context, right after the bridge**, so the captured image contains the bridge *and* the fully-initialized SDK. Restoring it gives a fresh isolate where the SDK is already present — no import, no evaluation. - -## Where it sits in the component model - -The [three components](/docs/architecture#the-big-picture) are unchanged. Snapshotting only changes *how* the executor's isolate is seeded: - -- **Client.** Builds the SDK bundle at package-build time and passes it to the sidecar as trusted VM configuration (`jsRuntime.snapshotUserlandCode`). It decides which agents opt in. -- **Sidecar.** Owns the snapshot. It builds the snapshot once, caches it process-wide, and seeds each session's isolate from it. The SDK runs inside the isolate under the same [permission policy](/docs/permissions) as any guest code — snapshotting grants the SDK no extra capability. -- **Executor.** The agent adapter restores into an isolate where the SDK is already on the global, reads it, and proceeds. It is untrusted guest code as always. - -## The pipeline - -### 1. Bundle the SDK to one snapshottable unit - -The agent SDK and its transitive dependencies are bundled (esbuild, IIFE) into a single file shipped with the agent package (`dist/sdk-snapshot.js`). The bundle evaluates the SDK and publishes its public API on a well-known global (e.g. `globalThis.__PI_SDK_RUNTIME__`). Node builtins stay external (resolved by the bridge's in-snapshot polyfills); heavy provider SDKs that are only reached via dynamic `import()` stay lazy and load post-restore from the VFS. - -### 2. Capture the evaluated SDK into the snapshot - -The sidecar runs the bridge, then the SDK bundle, in one snapshot-creation context, then serializes the heap. The result is a startup blob containing both. Per-session configuration (cwd, model, API keys) is **not** captured — it is injected after restore, so one blob serves every session. - -### 3. Cache it process-wide, keyed by content - -The blob is stored in a **sidecar-process-wide cache keyed by `sha256(bridge + bundle)`**. Any change to the bridge or the bundled dependency graph changes the key and triggers exactly one rebuild; an unchanged bundle is a cache hit. This is what makes it **build-once-per-sidecar**: the cache is shared across every VM and session in the process. - -### 4. Pre-warm so the first session is warm - -Building the snapshot is itself the expensive evaluation, just done once. To keep it off the session-create critical path, the sidecar **pre-warms** at VM creation: when a VM is configured with a snapshot bundle, the sidecar builds the blob into the cache *before* the first session is created. The first session then restores from a warm cache like every session after it. - -**Pre-warm and V8 initialization order** -The V8 platform must be initialized on a long-lived thread *before* any pre-warm runs. agentOS initializes the embedded runtime on the sidecar's main thread at startup. Initializing V8 lazily on a transient worker thread that then exits corrupts the platform and wedges later isolate creation — so the startup init is load-bearing, not incidental. - -### 5. Restore a fresh isolate per session - -On `openSession`, the agent's isolate is created from the cached blob. The SDK is already evaluated in the snapshot's default context, and each session gets a **fresh context cloned from it**. The adapter reads the SDK off the global instead of importing it. If no snapshot is configured — or snapshot creation fails — the adapter transparently falls back to the per-session dynamic-import path, so snapshotting never affects correctness, only latency. - -## Isolation - -Each session leases a **fresh context** cloned from the snapshot's default context. The captured SDK is shared read-only through the blob, but live state is not: a global, a captured-object mutation, or even a built-in prototype change made in one session is **not** observable in another. This is the same isolation guarantee as a non-snapshot session — a fresh isolate per session — and is covered by dedicated tests (a session that mutates `globalThis`, an SDK object, and `Array.prototype`, with a second session from the same snapshot seeing none of it). - -## Snapshot-safety: what an SDK must avoid - -A startup snapshot can only capture a pure JS heap. The SDK's **module-initialization** code (everything that runs at import time, before any function is called) must not, at top level: - -- Create a **native handle** — load a `.node` addon, instantiate WebAssembly, or produce any V8 *External* object (for example an ICU-backed `Intl.Segmenter` singleton). These cannot be serialized and abort snapshot creation. -- Open an **fd, socket, timer, or worker**, or leave a **pending promise** at the end of evaluation. -- Read **non-deterministic or per-session state** (`process.env`, cwd, model, `Date.now()`, `Math.random()`, a random UUID) into a module constant — it would be frozen to the build-time value. - -Real-world SDKs frequently break these by accident. agentOS makes such an SDK snapshottable with **build-time transforms in the bundle** that defer the offending work to first use (e.g. wrap a module-level native singleton in a lazy proxy, inline a top-level config-file read, convert eager fire-and-forget imports to synchronous module references). Each transform asserts the source shape it expects, so an upstream SDK change surfaces as a build error rather than a silent regression. The full author-facing rules live in the [Software Definition](/docs/custom-software/definition) reference. - -## Opt-in, per agent - -Snapshotting is **opt-in per agent**, via `agent.snapshot: true` on the [agent software descriptor](/docs/custom-software/definition), and requires the agent package to ship a snapshot-safe `dist/sdk-snapshot.js`. Today only the Pi agent opts in; other agents run the normal per-session import path. An agent qualifies by (1) being snapshot-safe and (2) building the bundle — there is nothing Pi-specific in the runtime mechanism. - -**Current trade-off** -The bundle is currently delivered inline in the (trusted) VM config, which moves bytes onto VM creation. The intended refinement is to ship the bundle as a build-time blob the sidecar loads from the guest VFS by path, keeping the config small. Either way the snapshot is built once per sidecar and reused across sessions. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/agent-sessions.md b/website/public/docs/docs/architecture/agent-sessions.md deleted file mode 100644 index 566ec61ba9..0000000000 --- a/website/public/docs/docs/architecture/agent-sessions.md +++ /dev/null @@ -1,51 +0,0 @@ -# Agent Sessions - -How durable sessions, ACP adapters, prompts, permissions, and history flow through AgentOS. - -An AgentOS session is a durable SQLite record with an optional live ACP adapter. The stable public session ID and the adapter's private ACP session ID are deliberately separate. - -## Ownership - -- **Actor:** lifecycle and `keepAwake` for active turns; one actor owns one VM. -- **Core SDK:** thin TypeScript or Rust transport and native ACP data types. -- **Sidecar:** session policy, SQLite transactions, adapter lifecycle, restore selection, and event delivery. -- **ACP adapter:** agent-specific private context and native protocol behavior. - -```text -client -> actor/core -> sidecar -> ACP adapter - ↘ VM SQLite event log -``` - -The sidecar—not the actor or SDK—owns defaults and orchestration. TypeScript and Rust send omitted fields as omissions and expose the same methods. - -## Turn lifecycle - -1. `openSession` creates the SQLite record and negotiates an adapter, or reuses the compatible existing record. It resolves without returning metadata. -2. `prompt` restores an unloaded adapter if needed. -3. AgentOS atomically marks the session running, records the prompt, and appends complete user-message ACP updates. -4. The prompt is dispatched exactly once. Live message/thought deltas are ephemeral; committed completed updates receive durable sequence numbers. -5. The prompt result and terminal idle/failed state commit atomically. Only then does the actor release `keepAwake`. - -One prompt may run per session. Cancellation races are first-writer-wins. AgentOS does not automatically replay interrupted prompts because tool side effects may already have occurred. - -The ACP runtime and AgentOS client transports impose no wall-clock deadline on prompts or human permission waits. After 30 seconds without ACP activity, AgentOS logs an inactivity warning with the total elapsed time and last observed activity, repeating every 30 seconds until activity resumes. Streaming output resets that interval. Bootstrap, teardown, filesystem, terminal, and other machine-to-machine operations retain bounded failure deadlines. Actor-hosted calls currently inherit RivetKit's maximum timer-safe action bound of about 24.8 days because RivetKit does not yet support an unbounded action. - -## Reads versus adapter operations - -`getSession`, `listSessions`, `readHistory`, and cached negotiation getters read SQLite without starting an adapter. `prompt` and configuration setters may restore one. `unloadSession` preserves SQLite while stopping the adapter; `deleteSession` removes both runtime and durable state. - -## Native ACP data - -Prompt content, stop reasons, session updates, configuration options, agent information, capabilities, and permission requests use upstream ACP shapes. AgentOS adds persistence envelopes and load/save semantics; it does not invent a parallel event vocabulary. - -ACP has no portable durable history-read method. Native restore is also inconsistent across real adapters, so adapter storage cannot be AgentOS's public history source. SQLite remains authoritative even if an adapter emitted output that failed to commit. - -## Adapter exits - -An unexpected adapter exit evicts the live route and fails the active turn. AgentOS does not respawn the adapter or replay work implicitly. The next explicit prompt can restore the session through native resume/load or the bounded continuation fallback. - -## Next - -- [Sessions](/docs/sessions) for the public API. -- [Sessions & Persistence](/docs/architecture/sessions-persistence) for SQLite and restoration. -- [Approvals](/docs/approvals) for ACP permission options. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/compiler-toolchain.md b/website/public/docs/docs/architecture/compiler-toolchain.md deleted file mode 100644 index 6a2af19de5..0000000000 --- a/website/public/docs/docs/architecture/compiler-toolchain.md +++ /dev/null @@ -1,102 +0,0 @@ -# Compiler Toolchain - -How agentOS compiles its command suite to WebAssembly: Rust coreutils via cargo and C programs via wasi-sdk, linked against a patched wasi-libc plus the wasi-ext bindings, and how the resulting .wasm files become the guest's commands. - -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. - -The commands a guest runs through [process execution](/docs/processes), the shell -(`sh`) and the coreutils behind it, are not native host binaries. They are -WebAssembly modules compiled ahead of time and mounted into the VM. This page -covers how that command suite is produced: which toolchains compile it, what it -links against, and how the resulting `.wasm` files become the guest's commands. - -For *why* WASM is a first-class guest and *how* it presents a POSIX surface at -runtime, see the [WASM VM](/docs/architecture/posix-syscalls) page. This page is the build-side -counterpart: it documents the toolchain that emits binaries carrying both -[the host-import layer and the WASI shim](/docs/architecture/posix-syscalls). - -## Target: `wasm32-wasip1` - -Everything in the command suite is compiled to a single target, -`wasm32-wasip1`: the WASI preview 1 ABI on the 32-bit WebAssembly architecture. -Picking one target for the whole suite means a single libc, a single set of -host import declarations, and a single runtime shim can serve every command. - -A guest module built for this target expects standard WASI (preopened file -descriptors, clocks, randomness, file I/O) plus the extra agentOS import modules -described below. Both halves are satisfied at runtime by the kernel-backed -runtime; nothing in a compiled command reaches a real host syscall. - -## Two source languages, two compilers - -The suite is heterogeneous: most tools are Rust, some are C. Each language uses -its own compiler driver, but both emit the same `wasm32-wasip1` ABI and link -against the same sysroot, so the outputs are interchangeable at runtime. - -- **Rust coreutils** are built with **`cargo`** targeting `wasm32-wasip1`. Rust's - standard library already has first-class support for this target, so the - coreutils crates compile with an ordinary cross-compile invocation. -- **C programs** are built with the **`wasi-sdk`** toolchain, a packaged - `clang` plus sysroot tuned for WASI. C tools that have no Rust equivalent (or - that are easier to carry as upstream C) go through this path. - -```bash -# Rust coreutils -cargo build --target wasm32-wasip1 --release - -# C programs via wasi-sdk, linked against the patched libc + wasi-ext -$WASI_SDK/bin/clang --target=wasm32-wasip1 \ - --sysroot=$WASI_SYSROOT \ - -lwasi-ext \ - tool.c -o tool.wasm -``` - -## What every binary links against - -Regardless of source language, each command links against the same two pieces. -Together they give a single binary both the standard WASI calls and the agentOS -process / user / network extensions. - -- **A patched `wasi-libc`.** The libc is the WASI standard library, modified so - that the calls a normal command-line program performs resolve against the - agentOS surface instead of failing or hitting unimplemented stubs. This is the - same patched libc the [Layer 2 shim](/docs/architecture/posix-syscalls) adapts at runtime; the - build side and the runtime side are two ends of the same contract. -- **The `wasi-ext` bindings.** These declare the extra WebAssembly import - modules (`host_process`, `host_user`, `host_net`, and the small - `host_sleep_ms` binding) that base WASI cannot express. Linking `wasi-ext` - into a binary is what lets its libc emit `fork` / `exec`, `getuid` / `getgid`, - and `connect` / `listen` as ordinary-looking syscalls that the host runtime - then services through the kernel. See - [Layer 1: custom host import modules](/docs/architecture/posix-syscalls) for the runtime half. - -The import declarations are compile-time only: linking `wasi-ext` tells the -module *which* host imports to reference, but the calls are still routed through -the kernel and gated by the VM's [permission policy](/docs/permissions) at -runtime. Building against `host_net` does not grant network access. - -## From `.wasm` to a guest command - -The compiler toolchain's product is a set of `.wasm` files, one per command. -Those files are what the runtime mounts as the guest's executables: when a guest -invokes `ls`, `sh`, or any other bundled tool, the kernel resolves the name to -the corresponding module, instantiates it with the host imports and the WASI -shim wired in, and runs it as a [child process](/docs/processes) with real -process, user, and network semantics, all virtualized. - -The same path is open to your own programs. A program you compile for -`wasm32-wasip1` runs as a guest command exactly like the bundled ones; link the -`wasi-ext` bindings if it needs processes, users, or sockets, and leave them out -for a pure-compute tool. Heavy native binaries that are not yet available as -WASM belong in an [external sandbox](/docs/sandboxes) instead. - -## Recommendations - -- Use the bundled WASM coreutils and `sh` for normal shell workloads; they - already carry the patched libc and the `wasi-ext` extensions. -- To ship your own command, compile it for `wasm32-wasip1` with `cargo` (Rust) - or the `wasi-sdk` `clang` (C), and link `wasi-ext` only if it needs the - process / user / network host imports. -- Keep the build and runtime contracts aligned: the patched `wasi-libc` and the - `wasi-ext` import declarations a binary is compiled against are the same ones - the [WASM VM](/docs/architecture/posix-syscalls) runtime expects to satisfy. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/filesystem.md b/website/public/docs/docs/architecture/filesystem.md deleted file mode 100644 index c40b7a0f78..0000000000 --- a/website/public/docs/docs/architecture/filesystem.md +++ /dev/null @@ -1,94 +0,0 @@ -# Filesystem - -Internals of the kernel VFS: the overlay/mount/root engines, how guest fs syscalls are routed and confined, WASM preopens, and mount confinement against symlink and .. escapes. - -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. - -This page is an internals deep-dive on the **kernel virtual filesystem (VFS)**: how it is layered, how a guest `fs` syscall is routed through it, and how guest I/O is confined to the VM. For the user-facing API (reading, writing, mounting, persistence), see [Filesystem](/docs/filesystem). - -The invariant this whole subsystem exists to uphold: **every guest filesystem operation is serviced by the kernel-owned VFS, never by a real host capability.** There is no host disk reachable from the guest. The VFS presents normal Linux semantics to tools while keeping every byte inside the kernel. - -The security boundary is sidecar to executor. The VFS lives inside the trusted sidecar; the guest in the executor only ever *asks* for a filesystem operation. Confinement is the kernel's job, not the guest's. See the [Security Model](/docs/security-model) for the full threat model. - -## Where the VFS sits - -A guest `fs` call never touches the host. The path is always: - -``` -guest fs call (executor) - -> kernel syscall (crosses sidecar <-> executor boundary) - -> VFS engine resolves the path - -> backing store services the operation - -> result returns to the executor -``` - -- The executor holds **no** filesystem capability of its own. It issues a syscall and blocks for the reply. -- The kernel checks the applied permission policy for the filesystem scope before servicing the request. -- The VFS resolves the path against the VM's layered engines, then services the operation against the engine that owns that path. - -Because every byte is mediated here, two properties fall out for free: the guest can never reach the real host disk, and one VM's filesystem is never visible to another VM. Isolation is per-VM. - -## The VFS engines - -The per-VM filesystem is not a single flat store. It is a tree of **engines**, each responsible for a subtree of the namespace. A path is resolved by walking from the root engine down to whichever engine owns the deepest matching prefix, then handing the remainder of the path to that engine. - -- **Root engine.** Owns `/` and the base namespace. Every VM boots with a root filesystem bootstrapped from a snapshot, so the guest starts against a populated POSIX tree (the default working directory is `/home/agentos`). -- **Overlay engine.** Composes layers so writes land in a writable upper layer while reads fall through to a lower layer. This is how a read-mostly base can be presented as writable to the guest without mutating the shared lower layer. -- **Mount engine.** Grafts a distinct backing store onto a guest path (a mount point). Below the mount point, operations are routed to that mount's backend instead of the parent engine. This is the mechanism behind in-memory, host-directory, S3, and Google Drive mounts. - -Resolution is **longest-prefix wins**: if `/mnt/data` is a mount and the guest opens `/mnt/data/file`, the mount engine services it; anything outside `/mnt/data` stays with the parent (root/overlay) engine. - -``` -/ <- root engine (bootstrapped from snapshot) -|- home/user/... <- root / overlay -|- mnt/ -| |- scratch/... <- mount engine -> in-memory backend -| |- code/... <- mount engine -> host-directory backend (read-only) -| \- data/... <- mount engine -> S3 backend -\- ... -``` - -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](/docs/filesystem#mounts) for the user-facing config. - -## Routing a guest syscall - -When the guest calls, say, `readFileSync("/mnt/data/report.csv")`: - -1. **Permission check.** The kernel verifies the filesystem scope is granted for that operation. Nothing is bound by default; access is denied until opted in (see [Permissions](/docs/permissions)). -2. **Engine resolution.** The VFS walks the namespace and selects the engine owning the longest matching prefix (`/mnt/data` -> the S3 mount engine). -3. **Path normalization and confinement.** The remainder of the path is normalized within the owning engine's root. `.` and `..` segments are resolved *before* the operation reaches the backend, so the request cannot climb above the engine's root. -4. **Backend operation.** The owning engine's backend services the read/write/stat/etc. against its store (in-memory pages, the persisted base, a host directory, S3, ...). -5. **Reply.** The result crosses back to the executor, which unblocks. - -Host-side APIs (`agent.writeFile`, `agent.readFile`) enter the *same* VFS from the trusted side, which is why the host can seed and read files the guest sees, without ever exposing the real host disk to the guest. - -## Mount confinement - -A host-backed mount (host directory, S3, ...) comes from trusted config, so its existence, target, and credentials are not attack surface. What *is* in scope is the guest-driven traffic through it: the guest must not be able to use a mounted path to reach bytes outside the mount root. Confinement is enforced by the kernel, on every operation: - -- **`..` traversal.** Path segments are normalized relative to the mount root before the backend sees them. A guest path like `/mnt/code/../../etc/passwd` cannot resolve above the mount root; it is clamped to the mount's own subtree (and, above the mount point, handed back to the parent engine, which is itself the kernel VFS, not the host). -- **Symlinks.** Symlink resolution (`realpath` following) is performed by the kernel against the *virtual* namespace, not the host's. A symlink inside a host-directory mount cannot be used to escape the mount root onto the wider host filesystem; the resolved target is re-confined to the mount root. -- **Path aliasing / TOCTOU.** Because resolution and confinement happen inside the kernel on each operation, there is no window where the guest resolves a path and the backend later acts on a different one. The guest sees only the mounted subtree, never the wider host filesystem. - -Mounts for host and remote backends are **read-only by default**; a writable mount must be opted into explicitly. The `readOnly` flag is enforced at the engine, so a write syscall to a read-only mount fails inside the kernel rather than reaching the backend. - -"Trusted mount, untrusted traffic": the mount's target is trusted configuration, but the guest drives I/O through it, so confining guest operations to the mount root (`..`, symlink, TOCTOU, path-aliasing) is squarely in scope and enforced by the kernel. - -## WASM preopens - -WASI does not grant a WASM guest an ambient filesystem. Instead, the host hands the module a set of **preopened directories**: capability handles to specific subtrees, and the guest can only reach paths reachable from a preopen. - -In agentOS these preopens are wired to the **same kernel VFS** rather than to host directories: - -- A preopen maps a guest-visible path to a VFS subtree. File descriptors derived from it are serviced by the VFS engines above, with the same confinement rules. -- The WASM guest therefore sees the virtualized filesystem (root snapshot, overlays, mounts) through standard WASI calls, with no host filesystem handle anywhere in the chain. -- Confinement composes: a preopen rooted at a mount point inherits that mount's `..`/symlink confinement, because resolution still runs through the kernel VFS. - -The result is that WASI filesystem access and the V8/Node `fs` path converge on one virtual filesystem, so both executor flavors get identical isolation and identical Linux semantics. - -## Where to go next - -- [Filesystem](/docs/filesystem): the user-facing API for reading, writing, mounting, and persistence. -- [Architecture](/docs/architecture): the components, trust boundary, and kernel-owned syscall paths. -- [Permissions](/docs/permissions): the filesystem scope the kernel checks on every operation. -- [Security Model](/docs/security-model): the full trust model and threat boundary. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/javascript-executor.md b/website/public/docs/docs/architecture/javascript-executor.md deleted file mode 100644 index e494bcb58c..0000000000 --- a/website/public/docs/docs/architecture/javascript-executor.md +++ /dev/null @@ -1,284 +0,0 @@ -# JavaScript Executor & Socket Reactor - -How the process-wide Tokio runtime, bounded socket tasks, durable readiness state, capacity-one VM wakes, and thread-affine V8 executor cooperate without running guest JavaScript on Tokio. - -This page is an internals deep-dive on the boundary between the trusted -sidecar reactor and the untrusted JavaScript executor. It explains which work -runs as a Tokio task, how a socket makes the V8 executor runnable, which -channels carry data, and how Node stream backpressure reaches the actual -transport. - -For socket ownership, loopback, DNS, and network policy, see -[Networking](/docs/architecture/networking). For the client-facing JavaScript -environment, see [JavaScript](/docs/javascript). - -Tokio never invokes guest JavaScript from a runtime worker. A Tokio task stores -bounded work and publishes durable readiness. The separate V8 executor thread -notices a capacity-one wake and enters its own isolate. - -## Process and thread topology - -The sidecar process owns one fixed-worker, multithreaded Tokio runtime. Every -VM and subsystem shares it. Socket readers and writers, listeners, UDP, TLS, -HTTP/2, DNS, timers, protocol work, and lightweight VM supervisors are async -tasks scheduled on those workers. - -A Tokio task is not a dedicated thread. It is a future that may be polled by -different runtime workers over its lifetime. A sidecar may have thousands of -admitted handle tasks without creating thousands of OS threads. - -Guest V8 execution is deliberately different: - -- Each active JavaScript session receives an admitted, thread-affine V8 - executor. -- The executor is a real OS thread outside Tokio. It owns the isolate and is - the only non-V8 platform thread that enters that isolate. -- Synchronous guest JavaScript or a synchronous bridge wait can block that - executor, but cannot occupy a Tokio worker or another VM's executor. -- The number of active and warm executor threads is bounded separately from - socket and task counts. - -There is therefore no "Tokio task running a Node.js process." Trusted I/O runs -as Tokio tasks; untrusted JavaScript runs on a V8 executor thread. - -## One TCP read, end to end - -[![Sequence from OS readiness through Tokio, durable readiness, the V8 executor, and the guest JavaScript socket read pump.](/images/architecture/javascript-executor-wakeup-sequence-dark.svg)](/images/architecture/javascript-executor-wakeup-sequence-dark.svg) - -The sequence has two paths that must not be conflated: - -- The **wake path** carries only enough information to make the correct V8 - executor inspect durable state. -- The **data path** retains charged bytes in the kernel or a bounded socket - completion queue until JavaScript explicitly drains them. - -### 1. The OS wakes a Tokio task - -On Linux, Tokio's `mio` driver registers the socket with `epoll`; other -platforms use their equivalent readiness mechanism. When the descriptor -becomes readable, Tokio schedules the socket reader future on a runtime worker. -Readiness means that a bounded nonblocking read is likely to make progress. It -does not contain the bytes. - -The reader acquires its fairness turn, reads at most its byte quantum, reserves -accounting for the result, and sends a `Data`, EOF, or error record into the -socket's bounded completion queue. If that queue or its byte budget is full, -the reader stops making transport progress. Remaining bytes stay in the kernel, -and TCP flow control eventually slows the peer. - -### 2. The task publishes durable readiness - -After storing deliverable work, the task publishes a flag such as `READABLE` -for the socket's opaque capability ID and generation. The VM-scoped -`ReadyState` owns one bounded map entry per admitted capability: - -```text -capability ID -> { - capability generation, - ready flags, - revision, - application read interest -} -``` - -Publishing merges the flag into that entry and increments its revision. It -does not append a readiness event. - -If the VM has no wake outstanding, the broker allocates a wake epoch and sends -one tiny `ReadyWake { generation, epoch }`. The implementation stages it -through a capacity-one Tokio MPSC and immediately transfers it into the V8 -executor's capacity-one crossbeam lane. While that wake is queued or in flight, -later publications only update durable state. - -**The wake contains no socket bytes, capability list, packet count, or revision -history.** It is a doorbell. - -### 3. The V8 executor notices the wake - -When the executor has no JavaScript work to run, its blocking crossbeam -selector waits on separate lanes for: - -- a readiness wake; -- ordinary bounded session commands; -- registered bridge completions; -- abort and shutdown control. - -The readiness message makes the V8 executor thread runnable. No Tokio worker -enters V8. If guest JavaScript is currently executing a long synchronous loop, -the wake remains outstanding and `ReadyState` continues coalescing work until -the executor can take another turn—matching Node's rule that I/O callbacks do -not interrupt synchronous JavaScript. - -### 4. Rust calls the guest dispatcher - -On the V8 executor thread, Rust calls `take_batch(epoch)` on the readiness -broker. This is the implementation of the conceptual `ready_batch` operation: -it snapshots at most the configured work quantum from durable state. It is not -a JavaScript function and is not a queue of all publications. - -The executor then enters its isolate and calls the guest global: - -```text -_agentOSReadyDispatch(capabilityId, capabilityGeneration, flags) -``` - -The bridge keeps a JavaScript map from `(capability ID, generation)` to a -readiness target. For a `NetSocket`, the target records a pending read wake and -queues one JavaScript microtask for the socket read pump. Generation is part of -the key, so a late wake for a destroyed socket cannot target a replacement -capability that reused its numeric ID. - -### 5. JavaScript drains the actual bytes - -The socket pump invokes the bounded raw `net.socket_read` bridge operation. -That operation drains the socket completion queue and returns bytes through -the call's registered response target. A synchronous form blocks only this -VM's executor while it waits; it does not scan or defer ordinary session -events and does not block Tokio. - -The bridge hands returned bytes to Node's `Readable` implementation: - -```text -Readable.push(bytes) -``` - -`Readable` is the readable half of the guest's real `Duplex` socket stream. -`push()` adds bytes to its JavaScript-side input buffer and returns whether -that buffer remains below its high-water mark. - -After the bounded turn, the executor calls `complete_batch()` with the -revisions it observed. This is the implementation of the conceptual -`complete_wake` operation. An acknowledgement clears a flag only if the -entry's revision is unchanged; newer work cannot be erased by an older batch. - -## Revisions and wake epochs - -[![State machine showing repeated readiness coalescing, revision-safe acknowledgements, replacement wake epochs, and stream backpressure.](/images/architecture/javascript-executor-readiness-state-dark.svg)](/images/architecture/javascript-executor-readiness-state-dark.svg) - -Revisions and epochs solve different races: - -- A **revision** belongs to one capability entry. It changes when that - capability publishes newer deliverable state or its readable state is - invalidated. -- An **epoch** belongs to one VM wake cycle. It identifies the single wake - currently queued or being processed. - -Suppose V8 snapshots socket 42 at revision 9. Before it acknowledges the batch, -the socket task publishes more data and advances the entry to revision 10. -The revision-9 acknowledgement no longer matches, so it cannot clear -`READABLE`. Completing the old epoch atomically observes that work remains and -queues one replacement epoch. - -There is no revision queue. Revisions 8, 9, and 10 are successive values of one -integer in one bounded map entry. Likewise, `READABLE` is one level bit rather -than one message per packet. - -## Backpressure reaches the transport - -If `Readable.push(bytes)` returns `false`, the guest buffer has reached its -high-water mark. The socket bridge: - -1. clears application read demand; -2. sends `SetReadInterest(false)` to the capability; -3. suppresses or clears deliverable `READABLE` state; and -4. leaves the Tokio reader waiting instead of repeatedly polling a - level-readable descriptor. - -Already admitted bytes remain in charged completion state. Additional bytes -remain in the OS receive buffer, and TCP applies pressure to the sender. - -When the consumer drains the JavaScript buffer, Node calls the socket's -`_read()` method. `_read()` is a standard `Readable` hook: it means the stream -wants more input. The bridge sends `SetReadInterest(true)`, wakes the reader, -and republishes readiness if source work is already known. - -`ref()` and `unref()` are unrelated to this mechanism. They affect whether the -socket keeps the JavaScript execution alive; they never pause I/O or suppress -callbacks. Only stream demand controls application read interest. - -## Channel map - -| Path | Primitive | What it carries | Bound and full behavior | -| --- | --- | --- | --- | -| OS to socket task | Tokio readiness registration | A readiness edge/level | No payload queue; task performs a bounded turn | -| Socket reader to capability | Bounded async completion channel | Charged `Data` bytes, EOF, error, close | Count and bytes bounded; full pauses the reader | -| Socket writer commands | Bounded Tokio MPSC plus reservations | Ordered writes, shutdown, options | Safe admission waits or returns a typed overload | -| Capability readiness | Revisioned map | Latest flags per capability | Cardinality bounded by admitted capabilities | -| Broker wake staging | Tokio MPSC | `{ generation, epoch }` | Capacity one; repeated readiness coalesces | -| Executor wake | Crossbeam channel | `{ generation, epoch }` | Capacity one; selected by the V8 thread | -| Session commands | Crossbeam channel | Ordinary session work | Configured bound; not used for readiness payloads | -| Bridge result | Call registry and call-specific target | One registered result and reserved bytes | Direct settlement; never scans the session event lane | -| Abort/shutdown | Dedicated control lane | Cancellation or termination | Reserved separately from ordinary data | - -An MPSC capacity alone is not the backpressure design. Correctness comes from -combining bounded channels with durable state, byte reservations, source -pausing, call-specific response routing, and an explicit action for every full -condition. - -## Why this avoids deferred-event exhaustion - -The earlier synchronous bridge could wait for one host response while reading -a shared session-event stream. Every unrelated event encountered during that -wait had to be deferred. Once 256 unrelated messages accumulated, the -synchronous bridge failed even though the host tool response itself was -successful. - -The reactor removes that dependency cycle: - -- A registered bridge response settles its call-specific waiter directly. -- Socket readiness merges into bounded `ReadyState` and one wake instead of - entering the ordinary event stream. -- Socket bytes live in a separately bounded completion queue. -- Abort and shutdown use reserved control paths. - -Consequently, a flood of ordinary session updates cannot sit in front of the -response that a synchronous call needs, and a hot socket cannot manufacture -one cross-boundary event per packet. - -## Relationship to Node.js - -AgentOS copies Node's evented-I/O invariants, not its process topology. - -| Concern | Node.js | AgentOS | -| --- | --- | --- | -| I/O runtime | One libuv loop per Node process | One Tokio runtime shared by the sidecar process | -| JavaScript execution | Event-loop thread enters V8 | Separate admitted V8 executor thread enters its isolate | -| Descriptor ownership | Node owns native descriptors | Trusted sidecar owns descriptors; guest sees opaque capabilities | -| Readiness callback | libuv calls the stream binding directly | Durable state plus one coalesced wake crosses the security boundary | -| Read backpressure | `push(false)` stops `uv_read_start` activity | `push(false)` disables capability application-read interest | -| Resume | `_read()` restarts native reads | `_read()` restores sidecar read interest | -| Writes | libuv completion settles callbacks | One ordered per-socket bridge tail settles callbacks | -| Liveness | Referenced handles keep the loop alive | Referenced guest handles keep the execution alive | - -The extra readiness broker and bridge drain exist because the guest cannot own -host descriptors or let a trusted Tokio worker enter untrusted V8. They -preserve Node behavior across that security boundary. - -## Implementation guide - -The main pieces are: - -- `crates/runtime/src/readiness.rs`: revisioned `ReadyState`, wake epochs, and - interest gating. -- `crates/v8-runtime/src/session.rs`: the executor's bounded selector, - readiness batching, dispatch, acknowledgement, and executor admission. -- `crates/v8-runtime/src/stream.rs`: the Rust-to-V8 - `_agentOSReadyDispatch()` call. -- `packages/build-tools/bridge-src/builtins/readiness.ts`: the guest capability - target map. -- `packages/build-tools/bridge-src/builtins/net.ts`: `NetSocket`, the - readiness-driven read pump, `Duplex` backpressure, liveness, and ordered - writes. -- `crates/native-sidecar/src/execution/network/`: sidecar-owned network tasks, - bounded completion state, and transport operations. - -## See also - -- [Networking](/docs/architecture/networking): kernel sockets, loopback, DNS, - and policy enforcement. -- [Processes](/docs/architecture/processes): how V8 executions fit into the - virtual process model. -- [Limits & Observability](/docs/architecture/limits-and-observability): - resource classes, queue bounds, warnings, and typed overload failures. -- [Security Model](/docs/security-model): why the sidecar owns capabilities and - the executor is untrusted. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/limits-and-observability.md b/website/public/docs/docs/architecture/limits-and-observability.md deleted file mode 100644 index d210d1bef5..0000000000 --- a/website/public/docs/docs/architecture/limits-and-observability.md +++ /dev/null @@ -1,87 +0,0 @@ -# Limits & Observability - -How agentOS bounds resources, applies backpressure, warns before a limit is hit, and surfaces it all to the host. - -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. - -agentOS runs untrusted, AI-generated code inside disposable VMs. Every resource -that code can consume is **bounded by default**, and every bound is designed to -**warn before it is hit**, **fail with a clear error when it is**, and stay -**inspectable** from one place. This page explains how the limits, backpressure, -logging, and observability pieces fit together across the stack. - -## Where limits live - -Limits are owned and enforced by the **agentOS kernel and sidecar**. The client -exposes the typed knobs and surfaces their signals. - -| Layer | Responsibility | -| --- | --- | -| agentOS kernel | Enforces per-VM resource caps (memory/heap, CPU time, fds, processes, sockets, filesystem bytes, …). | -| agentOS sidecar | Owns the bounded queues between the guest, the runtime, and the host; applies backpressure or rejects at the documented boundary; tracks usage. | -| agentOS client | Forwards `limits` config to the VM and surfaces limit signals to the caller. | - -## Limit contract - -Every bound — a resource cap, a bounded queue, a timeout, a payload size — -follows the same contract: - -1. **Bounded by default.** Nothing is unbounded out of the box. Memory is capped - at ~128 MiB per isolate (Cloudflare Workers parity), CPU is bounded, and every - queue has a fixed capacity. Operators may *raise* a cap, but never get an - unbounded default. -2. **Warn on approach where usage is measurable.** Resource and queue gauges emit - a structured warning as usage crosses a threshold (default **≥80%** of - capacity), once per crossing and re-armed only after recovery. Deadline-style - limits fail at their configured timeout instead of predicting future usage. -3. **Clear failure on breach.** Guest kernel resources return the corresponding - POSIX errno; host-facing queue and runtime failures name the limit and the - config path to raise it. Neither path silently drops data or crashes the host. - -## Backpressure, not catastrophe - -The path from guest code to the host is a **chain of bounded queues**: the V8 -runtime → a per-session frame channel → the V8→host event channel → the sidecar -stdout frame queue → the host. Streaming channels apply backpressure where the -producer can safely wait. Process/runtime delivery queues that cannot block -reject the crossing event with an error naming `limits.process.pendingEventCount` -or `limits.process.pendingEventBytes`. Neither path silently drops data or -crashes the sidecar. - -Buffer capacities are sized so that *transient* bursts are absorbed without ever -engaging backpressure; backpressure is the safety net for a genuinely stuck -consumer, not a normal-operation event. - -## The limit registry - -Live resource and queue gauges register with a single in-process **limit -registry**. Each registered limit tracks its live depth, high-water mark, and -capacity, and emits the near-capacity warning described above. This gives the -runtime one place to answer two questions: - -- *Is a limit about to be hit?* — the registry fires the approach warning. -- *What is the current usage of everything?* — a registry snapshot lists every - limit's depth / high-water / capacity / fill-percent for debugging. - -A CI audit fails the build if any limit-shaped constant is not classified and — -for operator-tunable ones — wired to a config field, so "is everything bounded -and config-wired?" is verified mechanically rather than by review. - -## Logging & host visibility - -The agentOS sidecar logs to **stderr** (never stdout — stdout is the framed wire -protocol). The default level is `WARN`, tunable with the `AGENTOS_LOG` -environment variable (`error` to quiet, `debug` for per-limit usage snapshots). -Near-limit warnings and backpressure events therefore show up in the sidecar's -stderr stream, which agentOS forwards to the host. - -The limit registry also exposes a structured **warning sink**: a callback that -fires on the same edge as the log, carrying `{ name, category, observed, -capacity, fillPercent }`. This is the foundation for host-facing limit -observability — a structured "a limit is approaching capacity" signal rather than -a parsed log line. - -## See also - -- [Resource Limits](/docs/resource-limits) — the full `limits` config surface. -- [Processes](/docs/architecture/processes) and [Sessions & Persistence](/docs/architecture/sessions-persistence) — the layers the queue chain runs through. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/networking.md b/website/public/docs/docs/architecture/networking.md deleted file mode 100644 index d826704b21..0000000000 --- a/website/public/docs/docs/architecture/networking.md +++ /dev/null @@ -1,135 +0,0 @@ -# Networking - -How the kernel socket table works: a single VM-local transport that carries host, JavaScript, and WASM traffic, where fetch / net / dns route through it, how egress policy and loopback confinement are enforced, and how preview URLs are served. - -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. - -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](/docs/networking). For the trust boundary this all sits inside, see [Architecture](/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. - -## The kernel socket table - -The socket table is the floor of the stack and the only component that actually moves bytes between two in-VM endpoints. It is per VM, so two VMs never share a listener or a connection. - -- It exposes POSIX-style primitives: `socket_create`, `socket_bind_inet`, `socket_connect_inet_loopback`, `socket_read`, `socket_write`, `poll_targets`. -- Every call is **owner-checked** (the calling process must own the descriptor) and **resource-accounted** against the VM's limits. -- Failures return correct POSIX errnos (`ECONNREFUSED`, `EACCES`, …) so guest code branches the way it would on real Linux. -- Connecting pairs two in-VM sockets and shuttles bytes between them. No host networking happens at this layer. - -Because every server is a kernel TCP listener, a client never needs to know whether the server it is talking to is JS, WASM, raw TCP, or HTTP. HTTP is layered on top of kernel TCP bytes, so every listener lives in the one table and is reachable identically. - -`AF_UNIX` `SOCK_STREAM` sockets follow Linux `sockaddr_un` rules: full-size pathname addresses stop at their first NUL, while a leading NUL selects the length-sensitive abstract namespace. Abstract names are losslessly encoded across the WASM boundary and mapped into a per-VM host namespace, so they cannot collide with another VM's sockets. Pathname sockets are real `S_IFSOCK` entries in the guest VFS and apply Linux directory, owner, group, mode, umask, symlink, rename, link, and unlink behavior. The transport files live under a unique host directory with mode `0700` and are removed with the VM. - -`AF_UNIX` has three explicit limits. Datagram and sequenced-packet Unix sockets return `ENOTSUP`; only streams are implemented. The current string-based VFS cannot represent invalid-UTF-8 filename bytes, so the WASM boundary returns `EILSEQ` instead of corrupting them (valid UTF-8 control characters are supported). Unix sockets on read-only host-backed mounts fail with `EROFS`, and sockets on writable host-backed mounts fail closed with `ENOTSUP`: host `bind(2)` and `connect(2)` have no descriptor-relative form that can preserve the mount confinement boundary. Symlinks into either kind of mount are rejected before a host socket is created. - -Blocking WASM `AF_UNIX` connect, accept, read/receive, and poll calls honor nonblocking mode and signals; accept and reads also honor `SO_RCVTIMEO`, returning Linux's `EAGAIN` when that socket timeout expires. Every blocking wait is additionally capped by `limits.resources.maxBlockingReadMs` (30 seconds by default); the runtime warns near the cap and returns `ETIMEDOUT` at the AgentOS safeguard. Raise that limit for workloads that intentionally wait longer. - -An earlier design carried two listener models at once: stream-mode listeners (`net.createServer`, WASM) on real kernel TCP sockets, and object-mode HTTP listeners (`http.createServer`) on a separate table that exchanged JSON request/response objects over stream events. A second guest process could not reach the object-mode table reliably, because the client expected byte-stream TCP semantics while the server only spoke object-mode dispatch. The current architecture removes the second model: everything is one socket table. - -## The four layers - -A request passes through four layers. Only the top and bottom understand HTTP; the middle two move bytes and enforce policy. - -| Layer | Role | Trust | Lives in | -| --- | --- | --- | --- | -| 4 · Guest bridge | `node:http` / `node:net` / `fetch` / undici shim | untrusted (V8 isolate) | `crates/execution/assets/v8-bridge.source.js` | -| 3 · Sync-RPC dispatch | routes `net.connect`, `net.http_request`, `net.listen`, … | trusted | `crates/sidecar/src/service.rs` | -| 2 · Execution & enforcement | listener state, host fetch client, permission checks | trusted (TCB) | `crates/sidecar/src/execution.rs` | -| 1 · Kernel socket table | `bind` / `listen` / `connect` / `read` / `write`, loopback routing | trusted (TCB floor) | `crates/kernel/src/socket_table.rs`, `kernel.rs` | - -### Layer 1: kernel socket table - -`crates/kernel/src/kernel.rs` exposes the primitives above. Loopback routing is the heart of VM-local networking: `socket_connect_inet_loopback` only succeeds against a socket that is actually bound and listening in the same VM's table; otherwise it returns `ECONNREFUSED`. Resource-limit checks run before the two sockets are paired. - -### Layer 2: sidecar execution (enforcement point / TCB) - -`crates/sidecar/src/execution.rs` is where policy is applied. Two roles matter for networking: - -- **Listener state.** `build_javascript_socket_path_context` walks every active process and records what is listening on which port, including a map of HTTP loopback targets keyed by `(family, port)`. This is the source of truth a connect consults to learn that, say, "port 3000 is an HTTP server owned by process X, server Y." -- **Host fetch client.** When the host calls `httpRequest` / `rt.fetch()`, the sidecar resolves the target to a VM-owned kernel listener, opens its own kernel socket, connects over loopback, and speaks HTTP/1.1 to the guest server. This is the only HTTP client that lives in the sidecar (the host has no guest isolate to do framing for it). - -### Layer 3: sync-RPC dispatch - -`crates/sidecar/src/service.rs` routes the bridge calls guest code makes. The guest-to-guest loopback HTTP path lands here as `net.http_request`. It is the most security-sensitive RPC, so it is guarded in order: - -1. The host must be a loopback address. -2. The applied network policy must permit the operation. -3. The requested `(process_id, server_id)` must match a listener that is currently live. - -That last check stops a guest from forging a target to reach a process it should not. - -### Layer 4: guest bridge - -`crates/execution/assets/v8-bridge.source.js` is the Node-compatibility shim inside the untrusted V8 isolate. It presents `node:http`, `node:net`, `fetch`, and undici to guest code and translates them into Layer 3 bridge calls. `http.createServer()` is implemented on top of `net.Server`: each accepted byte socket is parsed as HTTP and dispatched to the guest's request handler. - -## How fetch, net, and dns route through it - -- **`node:net` (raw TCP).** `net.connect` / `net.createServer` map directly onto kernel `connect` / `bind` + `listen`. The bytes are the payload; no framing is added. -- **`node:http` and `fetch`.** A guest HTTP server is a `net.Server` whose accepted sockets are HTTP-parsed in the bridge. A guest HTTP client runs undici over a kernel-backed dispatcher (or a raw serializer for the loopback fast path). Either way the bytes travel as kernel TCP. -- **DNS.** Name resolution is serviced by the kernel resolver, not the host. Outbound connections that leave the VM resolve through it, and the resolved addresses are then filtered by the egress allowlist (see below). DNS pinning ties the connection to the address that was checked, closing the resolve-then-reconnect TOCTOU gap. - -### Where HTTP meets TCP - -There is no shared HTTP/TCP translation module. Because the wire between every endpoint is raw TCP bytes through the kernel, HTTP is framed and deframed **at each edge that speaks HTTP**. The kernel (Layer 1) and the sidecar routing (Layer 2) never parse HTTP. There are three independent codecs, one per kind of endpoint: - -| Endpoint | Lives in | Encode / decode | -| --- | --- | --- | -| Guest HTTP server | guest bridge | `parseLoopbackRequestBuffer` (bytes to object), `serializeLoopbackResponse` (object to bytes), wired per accepted socket by `attachHttpServerSocket` | -| Guest HTTP client | guest bridge | undici over a kernel-backed dispatcher, or `serializeRawHttpRequest` + `waitForRawHttpResponse` | -| Host fetch client | sidecar execution | `serialize_kernel_http_fetch_request` (request to bytes), `parse_kernel_http_fetch_response` (bytes to JSON) | - -A WASM HTTP server or client does its own framing in guest code (reading the request line, writing a response with standard C socket calls). The kernel does not help it; it is just bytes, the same as for the JS endpoints. - -## Data flows - -- **Host to guest (`httpRequest` / `rt.fetch`).** The sidecar resolves the port to a VM-owned kernel listener, opens a sidecar-owned kernel socket, connects over loopback, serializes the request bytes, drives the target process forward so it can accept and respond, then parses the response bytes back into the host response object. It is **fail-closed**: no DNS, no external networking, no host-loopback fallback. If no VM-owned listener exists, it returns a missing-listener error. -- **Guest to guest.** `net.connect` goes through the sidecar, which returns a loopback HTTP target handle. The guest sends the request through `net.http_request`, which dispatches into the target process's request handler. Cross-process loopback passes through the enforcement point rather than taking an in-isolate shortcut. -- **Cross-runtime (JS and WASM, either direction).** Client and server connect through a kernel loopback socket pair and exchange raw bytes. JS to WASM, WASM to JS, and WASM to WASM all use the same path; only the side that runs the HTTP codec differs. -- **Guest outbound to host or external.** Connections that do not target a VM-owned listener take the external network path: permission checks, DNS pinning, then a real host `TcpStream`. Reaching a host loopback port still requires an explicit loopback exemption entry. - -## Egress policy and loopback confinement - -Guest networking is confined by three distinct controls plus the loopback-only default. The permission policy and limits are **trusted configuration**; the guest executor is the **untrusted subject** they bind. - -### Loopback-only by default - -Guest listeners are reachable only over loopback (`127.0.0.1` / `::1`) inside the VM. - -- Binding to `0.0.0.0` or `::` does not widen this: the kernel normalizes the unspecified address down to loopback, so the listener still answers only on loopback. -- A connection that originates outside the loopback interface and targets a port the VM does not own is refused with `EACCES`, noting the port is not exempt. -- This confinement is independent of the permission policy. Even with the network allowed, a guest server stays loopback-only unless its port is explicitly exempted. - -### Three stacked controls - -These are often conflated but are separate. They stack, and a request must pass every one that applies: - -1. **Permission policy** (`network.listen` / `network.connect`). Decides whether the guest may open a listener or initiate an outbound connection at all. A blocked operation fails with `blocked by network.listen policy` or `blocked by network.connect policy`. -2. **Loopback confinement.** Decides who may reach an already-permitted guest listener. By default only loopback inside the VM; a per-port exemption loosens it. -3. **DNS / egress allowlist.** Constrains where permitted outbound connections may go. The kernel filters resolved addresses, blocking outbound access to restricted ranges, so an allowed `connect` can still be refused by destination. - -The per-port loopback exemption belongs to layer 2 only. It is a trusted, per-port whitelist that *loosens* the default loopback confinement (for example, exposing an in-VM dev server beyond loopback). It is not an egress control and grants no outbound reach; layers 1 and 3 still apply. It is configured with `loopbackExemptPorts`, a list of ports that are exempt from the SSRF checks at layer 2; each listed port is reachable from outside the loopback interface, while the permission policy and egress allowlist continue to apply. - -### Trust and ownership - -Every guest connect, listen, read, and write passes through sidecar ownership and kernel owner checks. Guest-to-guest loopback is allowed only when the destination is a VM-owned listener and the applied network policy permits the connect. Host-loopback access from guest code is separate and still requires a loopback exemption plus the applied network policy. Long-lived waits must not block the sync-RPC path, so the stack uses stream events, bounded polling, and kernel socket waits with explicit timeouts. - -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. - -## 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 (`agent.expirePreviewUrl`) 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](/docs/networking): the `httpRequest` and preview URL API, with usage examples. -- [JavaScript Executor & Socket Reactor](/docs/architecture/javascript-executor): how Tokio readiness wakes V8, how the channel lanes are separated, and how Node stream backpressure reaches the transport. -- [Architecture](/docs/architecture): the client / sidecar / executor trust boundary this stack lives inside. -- [Security Model](/docs/security-model): the full in-scope and out-of-scope threat model. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/packages-and-command-resolution.md b/website/public/docs/docs/architecture/packages-and-command-resolution.md deleted file mode 100644 index d813ec103b..0000000000 --- a/website/public/docs/docs/architecture/packages-and-command-resolution.md +++ /dev/null @@ -1,209 +0,0 @@ -# Packages & Command Resolution - -How software is packaged, linked, resolved, and executed in an agentOS VM: a package is a directory, resolution is a $PATH walk, and a file's header picks its runtime. - -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. - -How a command name becomes a running program, and how the software that provides it -is packaged and linked. Everything is real files under -[`/opt/agentos`](/docs/architecture/filesystem) — there is no command registry; the -filesystem and `$PATH` are the only source of truth. For the host API that produces -packages, see [Software Definition](/docs/custom-software/definition). - -## Overview - - exec "pi" - $PATH walk over the VFS - /opt/agentos/bin/pi - a real symlink in the VFS - read header (binfmt) - #!…node - JavaScript · V8 - #!…python3 - Python · Pyodide - {'\\0asm'} - WebAssembly - ELF / Mach-O / PE - ENOEXEC - spawn under the VM permission policy - -- **Resolve** — a real `$PATH` walk over the VFS; the first executable match wins. -- **Dispatch** — by the file's *header* (`binfmt`): a `#!` shebang or a magic number. Never the name, never the extension. -- **Run** — on one of three runtimes: JavaScript (V8), WebAssembly, Python (Pyodide). See [Processes](/docs/architecture/processes). -- **Confine** — every process runs under the VM's single [permission policy](/docs/security-model). No per-command tiers. - -## Packages - -A package is a directory; its metadata is a normal `package.json` (`name`, `version`, -and a `bin` command map) plus a small `agentos-package.json` (the agentOS-specific -`name`/`agent`/`provides`). The shipped package contains **real files** — it's a plain npm -dependency. The `/opt/agentos///` tree below, with its `bin/` symlink farm, -is what the runtime **projects** from that package when it mounts it: - -``` -/opt/agentos/// -├── package.json # name, version, and the "bin" map (command → entry file) -├── agentos-package.json # agentOS metadata: name, optional agent block, provides -├── bin/ # symlinks the PROJECTION builds from package.json "bin" -│ ├── ls → ../libexec/coreutils # → multicall blob -│ └── vdir → ../libexec/coreutils # an "alias" is just another symlink -├── libexec/coreutils # helpers run by other programs, never on $PATH -├── node_modules/ | lib/ # support payload (a JS CLI's flat, self-contained closure) -└── share/man/man1/ls.1 # man pages and other FHS content -/opt/agentos//current → # version pointer; upgrade re-points it (atomic rename) -``` - -| Path | Contents | -|---|---| -| `package.json` | `name`, `version`, and a `bin` map (command → entry file). | -| `agentos-package.json` | agentOS metadata the sidecar reads on mount: `name`, an optional `agent` block, and any `provides` (files/env). Generated for command/WASM packages; carries the `agent` block for agents. | -| `bin/` | Command symlinks the projection builds from `package.json` `bin`; each basename is the command name. (Not part of the shipped package — npm can't carry symlinks.) | -| `libexec/` | Helpers invoked by other programs, never on `$PATH` (e.g. a multicall blob). | -| `node_modules/`, `lib/` | Non-executable payload — bundled deps and assets. | -| `share/` | FHS data — `share/man/man/*`, etc. | -| `current` | Symlink `→ `; switching versions is one atomic rename. | - -```json -// package.json — commands come from "bin"; an agent's ACP entrypoint is just one of them -{ "name": "@agentos-software/pi", "version": "0.0.1", "bin": { "pi-acp": "dist/pi-acp.wasm" } } -``` - -A directory is a **valid package** when: - -- **Commands come from `package.json` `bin`** (command → a real entry file), and each entry - **dispatches by header** — a magic number or `#!` shebang, no `.wasm`/`.js` extension or - `runtime`/`type` field; a headerless entry is `ENOEXEC`. The package ships **no symlinks** - (npm-safe); the runtime builds the `bin/` farm under `/opt/agentos` itself. -- **Aliases are symlinks** in the projected `bin/` farm — several names for one program (or a - multicall blob); `argv[0]` is the invoked name. -- **It is self-contained** — every import/require/asset resolves inside the package; nothing - comes from a host `node_modules`, pnpm store, or workspace at runtime - ([packaging](/docs/custom-software/definition) flattens/bundles deps in). -- **Minimal metadata** — `package.json` carries only the command set (`bin`) and `version`; there - is no command list beyond `bin`, no permission tiers (the [VM policy](#confinement--trust) - governs every command), and no dependency list. A small **`agentos-package.json`** alongside it - holds the agentOS-specific fields the sidecar reads when it mounts the package — the `name`, an - optional `agent` block, and any `provides` (files/env). The client never carries this on the - wire; it forwards only the package directory. - -## Linking - -Linking is creating the `bin/` symlinks in a `$PATH` directory. agentOS follows Homebrew: -`/opt/agentos/` is the cellar, and every command is symlinked into one managed prefix, -**`/opt/agentos/bin`**, which is on `$PATH`. The standard dirs (`/usr/bin`, `/usr/local/bin`, -`/bin`) stay ordinary writable Linux dirs — agentOS never writes to them. - - Searched left → right — first match wins (left shadows right) - /usr/local/sbin - /usr/local/bin - /opt/agentos/bin - /usr/sbin - /usr/bin - /sbin - /bin - agentOS links into /opt/agentos/bin; the rest are ordinary writable Linux dirs — drop a binary in /usr/local/bin to shadow an agentOS tool. - -| Software | Stored | Linked into | -|---|---|---| -| Base, mounted, and runtime-installed agentOS software | `/opt/agentos//` (or the mount) | `/opt/agentos/bin` | -| The user's own files | wherever they put them | `/usr/local/bin`, `/usr/bin`, … (normal) | - -- **Base & mounts** link into `/opt/agentos/bin` in a **read-only layer** projected from the - host and shared across VMs — the symlinks are real but cost nothing per boot. A mounted host - directory is linked the same way, with no copy. -- **Runtime installs** add symlinks to `/opt/agentos/bin` in the **writable layer** via - [`agentos-software link`](#the-agentos-software-cli) — ordinary symlinks, found by the normal walk. - -## Persistence - -Links and installed files are **filesystem entries**, so they persist exactly when their -[filesystem](/docs/architecture/filesystem) layer does — the same rule as VFS-persistent -`pip`. A snapshotted/persistent volume keeps runtime installs and links across restart; an -ephemeral one drops them on teardown. There is no package-specific persistence mechanism. - -Persisting a layer an untrusted guest can write to also persists whatever the guest linked -there. Treat a guest-writable `/usr/local/bin` as guest-controlled on restore (see -[Confinement & trust](#confinement--trust)). - -## Execution dispatch (binfmt) - -A resolved file's leading bytes are read into a fixed buffer and dispatched like the Linux -kernel's binary-format handlers. The command's **name plays no part** — `python3`, `node`, -and `pi` are runtimes only by virtue of their files' headers. - -| Header | Result | -|---|---| -| `#!` at bytes 0–1 (`binfmt_script`) | the interpreter named on the line | -| `\0asm` (`00 61 73 6d`) | WebAssembly runtime | -| `\x7fELF` / Mach-O / PE | **`ENOEXEC`** — foreign binary format, no native-arch handler | -| anything else | `ENOEXEC` (no implicit `/bin/sh` fallback here) | - -Shebang handling matches `binfmt_script`: - -- The interpreter path is **literal and absolute** — not `$PATH`-searched. `#!/usr/bin/env node` - works only because `/usr/bin/env` looks up its argument. -- At most **one** argument follows, **not** whitespace-split (`#!/usr/bin/env node --flag` passes - `node --flag` as a single arg). -- The header read is bounded to a fixed buffer (`BINPRM_BUF_SIZE`); a longer line truncates. - Interpreter chaining is depth-bounded (`ELOOP`); a missing interpreter is **`ENOENT`**, not `ENOEXEC`. - -**Shell fallback.** On `ENOEXEC`, a POSIX shell re-runs a headerless script via `/bin/sh`. That -retry lives in the shell ([agentos-shell](/docs/architecture/processes)), not the dispatcher, -which stays strictly `binfmt`-faithful. - -### Multicall (busybox-style) - -`bin/ls → ../libexec/coreutils` resolves at open to the shared `coreutils` blob. `argv[0]` is -the caller's value **verbatim** (`"ls"`) — never derived from the symlink — and the blob selects -its applet with `basename(argv[0])`, like busybox. Always invoke via the `bin/` name; calling the -blob by its own path yields an `argv[0]` that selects no applet. - -## Command resolution - -A `$PATH` walk over the [VFS](/docs/architecture/filesystem), full Linux semantics: - -- A name **containing `/`** bypasses `$PATH` and resolves directly (relative to cwd, or absolute). -- Otherwise each `:`-separated dir is searched in order; the first **executable** regular file - wins (execute bit required — a non-executable match yields `EACCES`). Left shadows right. -- An **empty `$PATH` element** (leading/trailing/`::`) means the **current working directory** — - the POSIX footgun, kept for fidelity. -- Matches are real VFS files/symlinks — `ls -l`-able, `stat`-able, removable, replaceable. The - filesystem is authoritative; there is no resolution cache to grow stale. - -## The `agentos-software` CLI - -``` -agentos-software link -``` - -- `` is a package directory or a node module directory (its `package.json` `bin` map is - the command list). -- It brokers a request to the sidecar, which owns the filesystem; the CLI has no privilege of - its own. -- Linked names are validated (no `/`, `..`, control chars, overlong names), and for a - guest-supplied package each symlink target must resolve inside the package root. - -## Confinement & trust - -Every process runs under the VM's single [permission policy](/docs/security-model) — like a -Linux process running with its user/namespace/container privileges, not privileges declared by -the binary. A package cannot grant itself permissions. The [trust boundary](/docs/security-model) -is the sidecar (trusted) vs. the guest (untrusted): - -- **Linking changes discoverability, not privilege** — the policy is enforced at spawn, - regardless of how a command was found. -- **Shadowing is allowed, Linux-style** — a guest may drop a `node`/`ls` into a writable `$PATH` - dir; trusted in-VM components defend by invoking tools via **absolute paths** (or a `$PATH` - that excludes guest-writable dirs). The shadowing binary still runs only under the VM policy. -- **Guest env is sanitized** like a privileged exec — `LD_*`, `DYLD_*`, `NODE_OPTIONS`, `PATH`, - `BASH_ENV`, `*PRELOAD` are stripped, as glibc does under `AT_SECURE`. -- **Trusted vs. guest packages** — symlink-escape checks apply only to guest-writable runtime packages. -- **Bounded** — the runtime link count is bounded; it warns on approach and fails with a typed - error naming the limit (see [Limits & Observability](/docs/architecture/limits-and-observability)). - -## See also - -- [Software Definition](/docs/custom-software/definition) — the host API that produces these packages. -- [Processes](/docs/architecture/processes) — the JavaScript, WebAssembly, and Python runtimes. -- [Filesystem](/docs/architecture/filesystem) — the VFS, layers, and persistence. -- [Security Model](/docs/security-model) — the trust boundary and VM permission policy. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/posix-syscalls.md b/website/public/docs/docs/architecture/posix-syscalls.md deleted file mode 100644 index bd91b30549..0000000000 --- a/website/public/docs/docs/architecture/posix-syscalls.md +++ /dev/null @@ -1,112 +0,0 @@ -# POSIX Syscalls - -How agentOS extends WASI in two layers so WebAssembly guests behave like normal POSIX programs on top of the kernel. - -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. - -Not everything inside an agentOS VM is JavaScript. The shell (`sh`) and the -coreutils behind [process execution](/docs/processes) ship as WebAssembly -binaries, and you can run your own WASM programs too. To make those programs -behave like normal Linux tools, agentOS presents a POSIX syscall surface on top -of WebAssembly. - -- **WASM is a first-class guest.** WASM binaries run beside JavaScript inside the same VM. -- **Same kernel, same boundary.** WASM syscalls route through the same kernel that backs JS guests, so there is no extra host access. -- **POSIX shape, not host access.** The extensions below add process, user, and network *semantics*, all virtualized. - -## Why WASI alone is not enough - -The base standard for WASM system access is **WASI** (specifically `wasip1`). -WASI is intentionally minimal: - -- It gives a guest preopened file descriptors, clocks, randomness, and basic file I/O. -- It has **no process model** (no `fork` / `exec` / `wait`). -- It has **no users or groups** (no `getuid` / `getgid`). -- It has **no general sockets** (no `connect` / `listen`). - -Real command-line programs expect all of those. agentOS closes the gap in two -layers, and both route through the kernel rather than the host. - -Every WASM syscall, like every JS syscall, goes through the kernel-owned virtual -filesystem, process table, and socket table. The extensions below add POSIX -*shape*; they do not add host access. See the [Security Model](/docs/security-model) -for the isolation boundary. - -## The two-layer model - -agentOS layers a POSIX surface over WASM. Layer 1 adds capabilities WASI does -not express at all; Layer 2 adapts the standard WASI calls so a normal libc -behaves correctly inside the VM. Both bottom out in the kernel. - - WASM guest (sh, coreutils, your .wasm) - compiled for wasm32-wasip1, linked against patched wasi-libc - - Layer 1: host import modules - host_process — spawn / wait - host_user — uid / gid - host_net — TCP sockets - host_sleep_ms — blocking sleep - - Layer 2: kernel-backed WASI shim - stdio through the kernel bridge - mounts mirrored as preopens - read-only tiers enforced - paths confined to their mount - - Kernel: virtual filesystem, process table, socket table - same paths that back JavaScript guests — no host escape - -## Layer 1: custom host import modules - -Standard WASI cannot express `fork` / `exec`, `getuid`, or `connect`. agentOS -declares extra WebAssembly import modules that the host runtime implements, so -guest libc can call them as if they were ordinary syscalls. These bindings live -in the `wasi-ext` crate and cover three areas: - -- **`host_process`**: process management. Spawn a child process (argv, env, inherited stdio fds, working directory), wait for a child to exit, and related file-descriptor operations. This is what gives a WASM `sh` real [child process](/docs/processes) semantics; spawns go through the kernel process table. -- **`host_user`**: user and group identity (uid, gid, user info). Base WASI has no concept of a user; this lets tools that call `getuid` / `getgid` see the VM's virtualized identity. -- **`host_net`**: TCP sockets (connect, listen, send, receive) through the kernel socket table, gated by the same [network permission policy](/docs/networking) as everything else. Base WASI has no general socket API. - -A small `host_sleep_ms` binding provides blocking sleep. Together these let a -guest compiled for `wasip1` behave as if it had a process model, user identity, -and a network, all virtualized. - -```c -// Imported from the host runtime, declared by the wasi-ext bindings. -// Guest libc calls these as if they were ordinary syscalls. -__attribute__((import_module("host_process"), import_name("proc_spawn"))) -int host_proc_spawn(const char *argv, const char *envp, int cwd_fd); - -// getuid returns an errno; the uid is written through the out-pointer. -__attribute__((import_module("host_user"), import_name("getuid"))) -int host_getuid(unsigned int *ret_uid); - -__attribute__((import_module("host_net"), import_name("net_connect"))) -int host_net_connect(int fd, const char *addr, int addr_len); -``` - -## Layer 2: the kernel-backed WASI shim - -The second layer adapts the standard WASI calls themselves so that programs -built against a normal libc behave correctly inside the VM. The embedded shim: - -- **Routes stdio through the kernel.** `fd_read` / `fd_write` on the standard descriptors go through the kernel stdio bridge rather than host file descriptors, so output stays inside the VM and honors PTYs and redirection. -- **Fills in libc expectations.** For example `fcntl(F_SETFL)` is serviced via `fd_fdstat_set_flags`, so flag changes that libc performs do not fail. -- **Mirrors mounts as preopens.** The preopen table reflects the VM's guest path mappings, so mounted directories are visible to WASM path resolution exactly as they are to JS and to `node:fs`. -- **Enforces read-only tiers.** `path_open` rejects create / truncate / write flags on read-only mounts while still allowing non-mutating opens (directory traversal, `O_DIRECTORY`), so read-only mounts stay read-only without breaking `find`, `ls`, and friends. -- **Confines paths to their mount.** Targets are resolved beneath the specific preopen's root, so `..` segments cannot escape one mount into a sibling mount or a host path. - -``` -fd_read(0) -> kernel stdio bridge (not a host fd) -fcntl(fd, F_SETFL) -> fd_fdstat_set_flags (libc flag changes succeed) -path_open("/data/x") -> resolved under the /data preopen root -path_open(..O_CREAT) -> rejected on a read-only mount -path_open("../../etc")-> stays inside the mount; cannot escape -``` - -POSIX record locks match Linux conflict, byte-range, close/exit-release, signal, -and deadlock behavior. In particular, `F_SETLKW` detects process wait cycles and -returns `EDEADLK`. The one intentional deviation is a finite safety cap: a -non-deadlocked wait that exceeds `limits.resources.maxBlockingReadMs` (30 -seconds by default) returns `ETIMEDOUT` instead of waiting indefinitely. Raise -that limit for workloads that intentionally hold locks longer. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/processes.md b/website/public/docs/docs/architecture/processes.md deleted file mode 100644 index fbf5c20153..0000000000 --- a/website/public/docs/docs/architecture/processes.md +++ /dev/null @@ -1,108 +0,0 @@ -# Processes - -Internals of the kernel process model: the virtual process table, how spawns are serviced, stdio bridging, PTYs, and how WASM sh and coreutils map onto it. - -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. - -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 -API (`process.exec`, `process.spawn`, `terminal.open`, lifecycle, the process tree), see -[Processes & Shell](/docs/processes). For the surrounding component and trust -model, see [Architecture](/docs/architecture). - -Two invariants frame everything below: - -- **No real host process is ever spawned for guest work.** Every guest process is an entry in a kernel-owned virtual process table, not an OS process. Guest JavaScript runs in V8 isolates; guest commands like `sh` and coreutils run as WebAssembly. Neither is `node` or a host binary. -- **Every process operation is a syscall into the kernel.** Spawning, waiting, signaling, reading stdout, and resizing a PTY all cross from the untrusted executor into the sidecar-owned kernel, which services them against virtualized resources. - -## The virtual process table - -Each VM owns one process table. It is the authority for what is "running" -inside that VM; nothing in it corresponds to a host PID. - -- **Per-VM and isolated.** Two VMs have two independent tables. A PID in one VM is meaningless in another, and processes are never visible across the VM boundary. -- **Holds every guest process,** not only the ones a client started explicitly. A `spawn` from the client, a child spawned by guest `node:child_process`, and the processes behind a shell pipeline are all table entries. This is why the system-wide views (`allProcesses`, `processTree`) can show more than what the client launched. -- **Tracks lifecycle and lineage.** Each entry carries its PID, the command and arguments, parent PID (so the tree can be reconstructed), running/exited status, exit code once collected, and its attached stdio endpoints. -- **Records a driver.** An entry knows which execution backend services it (for example a V8 isolate versus a WASM runtime). This is the `driver` field surfaced on `allProcesses`. Drivers differ in *how* the code runs; they share the same table, the same kernel-owned stdio, and the same boundary. - -The process table is part of the kernel the sidecar owns. The executor never mutates it directly; it can only ask the kernel to create, wait on, or signal an entry. That request-only relationship is the sidecar-to-executor boundary applied to processes. - -## How a spawn is serviced - -A spawn, whether it originates from a client `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. -2. **Permission check.** The kernel applies the VM's permission policy before doing anything. Process execution is denied by default and must be granted; 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 `exec` the kernel additionally collects stdout, stderr, and the exit code and returns them as the call's result; for `spawn` it leaves the process running and streams output via events. -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 a `wait`/`waitProcess` resolves against and what `processExit` reports. - -Signals (`stopProcess` / SIGTERM, `killProcess` / SIGKILL) 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 client-facing one-shot `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; -- the supplied pathname is resolved literally relative to the current working directory, without a `PATH` or basename fallback; -- `argv` and `envp` replace the old image's values exactly, including a custom or empty `argv[0]`; -- descriptors marked `FD_CLOEXEC` close at the image-commit point; and -- caught signal handlers reset to their defaults, while ignored dispositions remain ignored. - -For a WASM-to-WASM replacement, the sidecar commits the kernel state first and -the executor then swaps the module in place. This keeps runner-local pipe, -socket, and duplicated-descriptor state attached to the same process instead of -silently recreating it. `waitpid` reports an exit code and a terminating signal -as separate values, so a normal `exit(137)` is not confused with `SIGKILL`. - -## Stdio bridging - -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.** For `exec`, the kernel buffers stdout and stderr and hands them back when the process exits. For `spawn`, output is delivered incrementally as `processOutput` events tagged with the PID and the stream (`stdout`/`stderr`), and `processExit` signals completion. -- **Writable stdin.** `writeProcessStdin` pushes bytes into the process's stdin endpoint; `closeProcessStdin` 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 -whether the process is a V8 isolate or a WASM program; the driver writes to and -reads from kernel stdio, not from anything host-provided. - -## PTYs and interactive shells - -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 `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; everything the shell and its children emit comes back as `shellData` events. 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 - -The shell and the standard commands behind process execution are not special -host helpers; they are ordinary guest processes that happen to be WebAssembly. -For the full WASM execution model see [WASM VM](/docs/architecture/posix-syscalls); here is how it -maps onto the process table specifically. - -- **They are normal table entries.** Running `sh`, `ls`, `cat`, etc. allocates virtual PIDs and table entries exactly like any other process, with the WASM driver recorded on each. A pipeline of coreutils is several entries linked by kernel pipes. -- **POSIX process semantics are virtualized, not borrowed from the host.** Plain WASI has no process model (no `fork`/`exec`/`wait`). agentOS supplies those semantics through kernel-backed host imports, so a WASM program that spawns and waits on a child drives the *same* kernel process table that JS guests use. A coreutil spawning a subcommand is one table entry creating another. -- **Same stdio, same PTY.** WASM processes read and write the kernel stdio endpoints described above, and a shell built from WASM `sh` attaches to a kernel PTY just like any interactive shell. The driver differs; the kernel-owned plumbing does not. - -This is why the process model is uniform: whether an entry is a V8 isolate or a -WASM binary, it lives in the same per-VM table, goes through the same -permission-checked spawn path, and uses the same kernel-owned stdio and PTYs. - -## See also - -- [Processes & Shell](/docs/processes): the client API for running and managing processes. -- [WASM VM](/docs/architecture/posix-syscalls): how WebAssembly guests get POSIX process, user, and network semantics. -- [Architecture](/docs/architecture): components, the trust boundary, and the request lifecycle. -- [Permissions](/docs/permissions): the policy the kernel checks on every spawn. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/sessions-persistence.md b/website/public/docs/docs/architecture/sessions-persistence.md deleted file mode 100644 index b30a5e8653..0000000000 --- a/website/public/docs/docs/architecture/sessions-persistence.md +++ /dev/null @@ -1,84 +0,0 @@ -# Sessions & Persistence - -How AgentOS stores exact ACP history and restores adapters through VM SQLite. - -SQLite is the AgentOS source of truth for public session metadata, prompts, pending requests, and durable ACP events. Adapter-owned session files or databases remain private adapter state; AgentOS does not mirror them into the VFS or import adapter replay into public history. - -## One SQLite descriptor per VM - -VM creation supplies exactly one trusted database descriptor: - -- `actor_uds` talks directly to Rivet actor SQLite through its authenticated Unix socket. -- `sqlite_file` opens one local SQLite file for the logical VM on the sidecar's bounded blocking executor. - -The sidecar resolves the descriptor once and injects the same database handle into VFS metadata, VFS block storage, and the AgentOS core session store. Filesystem plugins receive only filesystem policy, not another SQLite path or UDS credential. One Rivet actor is one logical VM, so tables do not repeat a VM ID. - -Each actor-UDS transaction generates a fresh UUID transaction key and attaches it to `BEGIN`, every statement, and `COMMIT` or `ROLLBACK`. Rivet owns transaction affinity and isolation. AgentOS adds no second UDS mux, pool, writer scheduler, or retry layer. - -## Independent schema owners - -Three owners share the physical per-VM database without sharing a migration sequence: - -| Owner | Version table | Data tables | -|---|---|---| -| Native filesystem | `agentos_fs_schema_version` | `agentos_fs_*` | -| Sidecar/core durable state | `agentos_core_schema_version` | `agentos_core_*` | -| TypeScript actor hosting metadata | `agentos_actor_schema_version` | `agentos_actor_*` | - -Each version table is a `STRICT` singleton table. Its owner alone validates and advances its append-only migration ladder, updating the schema and version in the same transaction. A future version fails closed. There is no shared schema-version table, global AgentOS migration sequence, or AgentOS use of `PRAGMA user_version`; Rivet-owned schema metadata remains independent. Owners do not create cross-owner foreign keys. - -## Session event log - -`agentos_core_events` keeps the durable envelope in scalar columns: public session ID, sequence, timestamp, negotiated ACP version, internal storage kind, correlation ID, payload byte length, and permission outcome fields. `payload_json` contains only the exact native ACP payload: - -- `session_update` stores an ACP `SessionUpdate`, including its `sessionUpdate` discriminator, optional fields, and `_meta`. -- `permission_request` stores the ACP `RequestPermissionRequest` selected for public delivery. -- `permission_response` stores the ACP `RequestPermissionResponse`. - -The internal `session_update` storage kind is not a public event discriminator. On read, AgentOS exposes `SessionUpdate.sessionUpdate` as the event's top-level `type` and places that ACP variant's native fields directly beside it. Permission request and response fields are flattened the same way. The public AgentOS durability envelope is reconstructed from the scalar columns; it is not duplicated inside `payload_json`, and the row is not a raw JSON-RPC frame. This keeps event data ACP-native while giving AgentOS a stable sequence, timestamp, and public request correlation. - -Complete user content is committed before prompt dispatch. Agent message and thought deltas are live and ephemeral; they receive no durable sequence and are coalesced into native ACP chunk updates only at a completed-message boundary. Other ACP updates are stored unchanged. Events are published only after their SQLite transaction commits. If an adapter emitted an event that never committed, SQLite wins, and AgentOS never automatically resends a prompt whose delivery is uncertain. - -## Trusted plaintext storage - -The per-VM SQLite database is trusted runtime storage. Session environment values, MCP headers or credentials, prompts, message content, tool arguments and results, permission payloads, and cached adapter metadata may be stored as plaintext JSON or SQLite values so a session can restore after sleep. AgentOS does not currently encrypt, redact, or replace these values with secret references. Operators must protect database and backup access according to the sensitivity of the workload. - -## Retention and default bounds - -Defaults are generous, VM-configurable `limits.acp` safeguards. AgentOS warns at 80% and returns a typed error naming the setting to raise when a hard-admission limit is reached. - -| Durable collection | Default | Contract | -|---|---:|---| -| Sessions | 10,000 per VM | Hard admission limit; sessions are never evicted implicitly. | -| History | 1,000,000 events and 1 GiB per session | Oldest committed events are pruned in bounded batches; an older reconnect cursor returns `history_cursor_expired`. | -| Prompt/idempotency records | 100,000 per session; 1,000,000 per VM | Oldest unreferenced terminal records are pruned to admit new prompts. An idempotency key is authoritative only while its prompt record is retained. | -| Pending `ask` permissions | 1,000 per session; 10,000 per VM | Hard admission limit with no time-based expiry; lifecycle resolution is required. | -| Terminal permission outcomes | 10,000 per session; 100,000 per VM | Oldest outcomes are pruned. A late response gets its specific terminal reason while retained and `request_not_found` after pruning. | - -History counters and payload-byte totals are updated transactionally with insertion and pruning. Bootstrap reconciliation repairs counter drift from event rows. A single batch larger than the configured history event or byte bound fails atomically rather than partially committing. - -Related request bounds default to 64 MiB and 16,384 blocks per prompt, 4 MiB of fallback continuation context, and 10,000 rows per session-list or history page. - -## Adapter restoration - -Public session IDs do not depend on adapter IDs. When no live route exists, the sidecar starts the configured adapter and tries native ACP restoration in this order: - -1. `session/resume` when advertised by `sessionCapabilities.resume`. -2. Stable `session/load` when `loadSession` is advertised. -3. `session/new` plus bounded continuation context derived from recent SQLite history. - -Notifications replayed by `resume` or `load` are discarded. This avoids duplicate public history and accommodates adapters whose restoration behavior differs despite ACP negotiation. - -## Actor lifecycle - -Merely having durable sessions does not keep the actor awake. The prompt action uses actor `keepAwake` from dispatch through the terminal SQLite commit so the VM cannot sleep halfway through a turn. Read-only session operations never start an adapter and do not hold the actor awake. - -## Core tables - -- `agentos_core_sessions`: scalar session state and creation options, complex creation-option JSON, cached negotiation, retained-history counters, sequence bounds, and timestamps. -- `agentos_core_events`: ordered exact ACP payloads with a scalar AgentOS envelope. -- `agentos_core_prompts`: prompt idempotency hashes and terminal result or error; accepted input is represented by durable native ACP user updates rather than duplicate prompt JSON. -- `agentos_core_permission_records`: actionable and terminal permission correlation. -- `agentos_core_permission_outcomes`: bounded terminal outcomes used to answer late responses. - -The filesystem's `agentos_fs_*` and actor's `agentos_actor_*` tables share the database handle but remain independently owned. \ No newline at end of file diff --git a/website/public/docs/docs/architecture/tls-ssl.md b/website/public/docs/docs/architecture/tls-ssl.md deleted file mode 100644 index 97f85c5053..0000000000 --- a/website/public/docs/docs/architecture/tls-ssl.md +++ /dev/null @@ -1,58 +0,0 @@ -# TLS & SSL - -How agentOS uses in-guest mbedTLS plus a VM CA bundle for curl / wget / git, and a hermetic OpenSSL libcrypto build for OpenSSH. - -This is the internals view of how TLS works for guest CLI tools (`curl`, `wget`, `git`, `ssh`) that run as `wasm32-wasip1` in the untrusted executor. For how bytes actually move between endpoints, see [Networking](/docs/architecture/networking); for how the tools are compiled, see [Compiler Toolchain](/docs/architecture/compiler-toolchain); for the trust boundary this sits inside, see [Security Model](/docs/security-model). - -The governing rule: **verification happens in-guest, against a CA bundle shipped inside the VM.** The sidecar is a dumb ciphertext pipe — the untrusted guest never asks the trusted host to authenticate a server on its behalf. - -## Why HTTPS stays on mbedTLS - -OpenSSL can be built for agentOS's owned `wasm32-wasip1` sysroot, but it is not the right HTTPS backend for every command: - -- **The tools already have smaller TLS integrations.** curl has a maintained mbedTLS backend, git shares curl's libcurl, and wget only needs a compact implementation of its existing SSL abstraction. -- **The full toolkit is unnecessary there.** OpenSSL includes libssl, libcrypto, providers, engines, applications, modules, and platform assembly. HTTPS in these commands needs portable TLS, X.509 verification, and entropy, not that whole surface. -- **A scoped libcrypto build is still useful.** OpenSSH needs crypto primitives that its experimental `--without-openssl` mode omits. Its private OpenSSL build disables threads, assembly, dynamic modules, engines, applications, and libssl, and seeds from the owned libc's `getrandom` path. - -Sockets, DNS, and TCP were already real (the patched wasi-libc implements them over `host_net`). **Only TLS was the gap** — and before this work every tool shipped crippled: `curl` brokered TLS to the host (non-hermetic, wrong semantics), while `wget` and `git` had no HTTPS at all. - -## Replacing OpenSSL with mbedTLS - -We use **mbedTLS 3.6 LTS** as the in-guest TLS backend. It fits because it is **pure portable C99, single-threaded, zero platform dependencies**, does TLS 1.2/1.3 with X.509 verification, seeds entropy from a single `getentropy()` call, and — decisively — drops straight into C programs' existing TLS backends (curl already ships a first-class `USE_MBEDTLS` backend). - -Two artifacts make the whole class of tools work: - -1. **`libmbedtls` / `libmbedx509` / `libmbedcrypto`** built for `wasm32-wasip1` in the toolchain Makefile. -2. **A CA bundle inside the VM** at the common Linux path `/etc/ssl/certs/ca-certificates.crt`, with `/etc/ssl/cert.pem` pointing to it. Verification then runs in each tool's own code path against a trust store shipped in the VM — hermetic, with correct Linux exit codes and tool-specific trust overrides (`--cacert` / `CURL_CA_BUNDLE` for curl and `--ca-certificate` for wget). AgentOS generates the bundle at build time from an exact-pinned `webpki-root-certs` Mozilla snapshot and installs it directly in native and browser guest roots before the first execution, including read-only and restored roots. Explicit root-filesystem entries at either trust path take precedence. - -This provides the conventional file locations and Mozilla public roots, **not a byte-for-byte Debian or Alpine `ca-certificates` installation**. Distribution packages can select a different snapshot, add policy-managed or local roots, generate OpenSSL hash links, and provide tools such as `update-ca-certificates`; AgentOS does not imply those distro-specific files or update behavior. Supply a custom root-filesystem entry or use the tool-specific trust flags when you need a different trust policy. - -mbedTLS is **not** a general OpenSSL replacement — it lacks providers/engines, CMS/PKCS#7, the `openssl` CLI, and much of libcrypto's breadth. It **is** a complete replacement for OpenSSL's role as curl/wget/git's TLS backend, which is all an HTTPS client needs. - -## Per-tool compatibility - -### curl - -Uses upstream curl's own `USE_MBEDTLS` backend; the overlay is only WASI build fixes. Full HTTPS with real verification: `--cacert` parses via the VFS, a verify failure returns `CURLE_PEER_FAILED_VERIFICATION` (**exit 60**), and `curl -v` prints the chain. Content encodings `--compressed` (gzip / brotli / zstd) are enabled. - -### wget - -GNU wget ships **no** mbedTLS backend, so agentOS provides a hand-written one — `wasi_ssl.c` implements wget's four-function SSL abstraction (`ssl_init`, `ssl_cleanup`, `ssl_connect_wget`, `ssl_check_certificate`) over the same mbedTLS + CA bundle. This lights up HTTPS and FTPS (including control-to-data session resumption), `--ca-certificate` / `--ca-directory` / `--no-check-certificate`, client `--certificate` / `--private-key`, HSTS, and gzip. It is the only bespoke TLS backend in the tree. - -Wget's `--ciphers` accepts the common OpenSSL list surface: `DEFAULT`, `HIGH`, `ALL`, `!`/`-` exclusions, `+` reordering, standard algorithm classes, explicit IANA names, and names such as `ECDHE-RSA-AES128-GCM-SHA256`. A backend-specific token that cannot be translated (for example an OpenSSL `@SECLEVEL` directive) fails explicitly instead of silently broadening the TLS policy. - -### git - -git's HTTPS lives in the `git-remote-https` helper, which **links libcurl in-process** — git never shells out to a `curl` binary. agentOS builds a reusable, mbedTLS-linked libcurl and ships `git-remote-http` as a real command. Smart-HTTP **clone / fetch / push** work against GitHub/GitLab, with HTTP Basic auth (tokens, `GIT_ASKPASS`). git reuses curl's TLS entirely — there is no git-specific TLS code. - -### ssh - -ssh does **not** use mbedTLS. SSH transport crypto is not TLS, so OpenSSH 10.4p1 links a hermetic, static OpenSSL libcrypto built against the same owned sysroot. That restores the standard software algorithm families, including RSA and ECDSA host/user keys, DH and NIST ECDH key exchange, and AES-GCM/AES-CBC/3DES alongside ed25519, curve25519, and chacha20-poly1305. FIDO security-key key types, parsing, verification, agent-backed signing, and the isolated `ssh-sk-helper` protocol are enabled. Local enrollment and signing are unavailable today: the VM has neither a built-in libfido provider nor a `dlopen` bridge for an external provider, so those requests return the normal explicit provider-unavailable error. Direct PKCS#11 provider loading is disabled for the same missing host provider bridge. Host-key verification is fully enforced (fails closed on an unknown or changed key; `known_hosts` and `accept-new` are supported; no `StrictHostKeyChecking=no` default). It powers `git@host:` (git-over-ssh) and direct remote command execution. Kernel-backed `socketpair`, descriptor passing, `closefrom`, and process spawning preserve OpenSSH's `ProxyCommand` and `ProxyUseFdpass` behavior without granting host-process access. - -Three backgrounding operations fail explicitly instead of pretending to fork: `ssh -f` after authentication, ControlPersist master detachment, and the interactive `~&` escape. Each would require cloning a live authenticated continuation—WASM/V8 heap state plus the transport, channels, and pending packets—which the VM process model cannot snapshot. Ordinary pre-exec process spawning and helper commands retain Linux semantics. - -`VerifyHostKeyDNS` performs real SSHFP lookups and distinguishes NXDOMAIN from an empty RRset. SSHFP answers are treated as unauthenticated unless the resolver supplies authenticated DNSSEC proof; the current host resolver does not, so DNS can assist matching but does not set OpenSSH's secure-DNS flag. - -## Summary - -One mbedTLS build, one shared libcurl (curl and git), one hand-written wget backend, and a private OpenSSL libcrypto build for OpenSSH. TLS trust moved from "the host authenticates on the guest's behalf against the host's store" to "the guest verifies against a CA bundle shipped inside the VM." OpenSSL is not used by curl, wget, or git. \ No newline at end of file diff --git a/website/public/docs/docs/authentication.md b/website/public/docs/docs/authentication.md deleted file mode 100644 index 479317e0fa..0000000000 --- a/website/public/docs/docs/authentication.md +++ /dev/null @@ -1,16 +0,0 @@ -# Authentication - -Authenticate connections to agentOS actors using Rivet Actor connection params and hooks. - -agentOS uses the same authentication system as [Rivet Actors](/docs/actors/authentication): clients send credentials as connection params, and you validate them server-side. - -- Clients pass credentials in `params` when they connect. -- Validate them on the server in `onBeforeConnect` (throw to reject the connection), or extract user data into connection state with `createConnState` (read it in actions via `c.conn.state`). -- You can declare the credential shape with `agentOS(...)` to document what you accept, but the client's `params` is `unknown` and is not checked against it. The real check is your hook, not the types. -- AgentOS uses ordinary Rivet actor connection hooks, so authentication runs before the connection reaches an action. - -## Example - -The server declares the credential shape and validates it in `onBeforeConnect` (throw to reject); the client passes credentials as `params`. - -See [Actor Authentication](/docs/actors/authentication) for JWT validation, role-based access control, external auth providers, and token caching. \ No newline at end of file diff --git a/website/public/docs/docs/bash.md b/website/public/docs/docs/bash.md deleted file mode 100644 index 7758fe05c9..0000000000 --- a/website/public/docs/docs/bash.md +++ /dev/null @@ -1,38 +0,0 @@ -# Bash - -Run shell commands and arbitrary argv operations through the agentOS execution lifecycle. - -Run bash inside the VM. Shell commands are the simplest agentOS execution -surface, and share the same execution lifecycle as JavaScript, TypeScript, -Python, and package workflows. - -- **`process.exec()`**: Runs a bash command line. Use for pipes, redirects, globs. -- **`process.execFile()`**: Injection-safe; args are never parsed by a shell. -- **In-VM only**: Commands run inside the VM, never in the host shell. - -For multi-step work, consider letting the agent write [JavaScript](/docs/javascript) -or [Python](/docs/python) instead — one round trip and real data structures -rather than a chain of shell calls. - -## Run commands - -## Background and interactive work - -`spawn` starts a long-lived process and returns a `pid`. From there you get -stdin, a PTY, output replay, signals, and waiting. - -## Files and software - -Shell commands see the persistent [filesystem](/docs/filesystem) shared by -agents, JavaScript, and Python. Common POSIX commands ship by default; more is -projected through the [software registry](/docs/software). - -## Bindings - -[Bindings](/docs/bindings) appear as commands, so pipelines use trusted host -capabilities without putting credentials inside the VM. - -## Permissions, limits, and timeouts - -Every command inherits the VM [permission policy](/docs/permissions) and -[resource limits](/docs/resource-limits). \ No newline at end of file diff --git a/website/public/docs/docs/bindings.md b/website/public/docs/docs/bindings.md deleted file mode 100644 index 48770ba4a8..0000000000 --- a/website/public/docs/docs/bindings.md +++ /dev/null @@ -1,83 +0,0 @@ -# Custom Bindings - -Expose custom host functions to agents as CLI commands inside the VM. - -Expose your host JavaScript functions (defined with Zod input schemas) to agents as auto-generated CLI commands installed at `/usr/local/bin/agentos-{name}` inside the VM, injected into the agent's [system prompt](/docs/system-prompt) and callable inside scripts for code-mode token savings. - -## Getting started - -Define a bindings group with Zod input schemas and pass it to `agentOS()`. Each binding becomes a CLI command inside the VM. - -Each binding can set an explicit `timeout` (in milliseconds) for long-running work. Bindings run without a timeout unless one is set. - -### Zod to CLI mapping - -Zod schema fields are converted to CLI flags automatically. Field names are converted from camelCase to kebab-case. - -| Zod type | CLI syntax | Example | -|---|---|---| -| `z.string()` | `--name value` | `--path /tmp/out.png` | -| `z.number()` | `--name 42` | `--limit 5` | -| `z.boolean()` | `--flag` / `--no-flag` | `--full-page` | -| `z.enum(["a","b"])` | `--name a` | `--format json` | -| `z.array(z.string())` | `--name a --name b` | `--tags foo --tags bar` | - -Optional fields (via `.optional()`) become optional flags. Required fields are enforced at validation time. Use `.describe()` on Zod fields to generate useful `--help` output. - -### What the agent sees - -When bindings are registered, CLI shims are installed at `/usr/local/bin/agentos-{name}` inside the VM and the binding list is injected into the agent's [system prompt](/docs/system-prompt), so keep binding descriptions concise to save tokens. - -The agent interacts with bindings as shell commands: - -```bash -# List all available binding collections -agentos list-bindings - -# List bindings in a specific group -agentos list-bindings weather - -# Get help for a binding -agentos-weather forecast --help - -# Call a binding with flags -agentos-weather forecast --city Paris --days 3 - -# Call a binding with inline JSON -agentos-weather forecast --json '{"city":"Paris","days":3}' - -# Call a binding with JSON from a file -agentos-weather forecast --json-file /tmp/input.json -``` - -On success, the binding exits `0` and writes a JSON envelope to stdout: - -```json -{"ok":true,"result":{"temperature":22,"condition":"sunny"}} -``` - -On failure (validation or execution error), the binding exits non-zero and writes the error message to stderr: - -```text -Missing required flag: --city -``` - -## Bindings and MCP servers - -AgentOS supports two ways to give agents access to external functionality: **bindings** and session-scoped **MCP servers**. Both work, but they have different tradeoffs. - -| | Bindings | MCP Servers | -|---|---|---| -| **How it works** | Call JavaScript functions on the host directly | Connect to a standard MCP server | -| **Authentication** | None required. Direct binding to the agent's OS. | Requires custom auth configuration per server | -| **Code mode** | Built-in. Bindings are exposed as CLI commands, so agents can call them inside scripts for up to 80% token reduction. | Requires extra work to make code mode work out of the box | -| **Latency** | Near-zero. Bound directly to the host process. | Extra network hop to reach the MCP server | -| **Setup** | Define bindings in your actor code with Zod schemas | Configure any standard MCP server | - -Use bindings when you want to expose your own JavaScript functions to agents. Use MCP servers when you want to connect to existing third-party services. See [Sessions](/docs/sessions#open-a-session) for MCP server configuration. - -## Security - -Binding calls from the agent securely invoke your `execute()` functions on the host. Your functions run with full access to the host environment, so you can call databases, APIs, and services directly without proxying credentials into the VM. The agent never sees the credentials, it only sees the binding's input/output contract. - -Bindings run on the host with full access to the host environment, so do not expose bindings that could compromise the host without appropriate safeguards. \ No newline at end of file diff --git a/website/public/docs/docs/browser.md b/website/public/docs/docs/browser.md deleted file mode 100644 index dce60dace2..0000000000 --- a/website/public/docs/docs/browser.md +++ /dev/null @@ -1,39 +0,0 @@ -# Browser Automation - -Let agents read and search the web from an agentOS VM using Browserbase's cloud browser through the browse CLI — no local browser or sandbox required. - -Agents can read and search the web with the [Browserbase](https://www.browserbase.com) `browse` CLI. The page loads in a real browser in Browserbase's cloud and comes back as clean content — the VM never runs a browser. - -## Setup - -1. **Create a Browserbase account** - - [Sign up](https://www.browserbase.com/sign-up) and grab your API key and project id from the [dashboard](https://www.browserbase.com/settings): - - ```bash - export BROWSERBASE_API_KEY=bb_... - export BROWSERBASE_PROJECT_ID=... - ``` - -2. **Install** - - ```bash - npm install @rivet-dev/agentos @agentos-software/pi @agentos-software/browserbase - ``` - -3. **Add `browse` to the VM** - - Mount the [`browse` CLI skill](https://github.com/browserbase/stagehand/tree/main/packages/cli) into the agent's skills directory so it reaches for `browse` unprompted ([copy the skill folder from the example](https://github.com/rivet-dev/agentos/tree/main/examples/browserbase/skills)): - -4. **Use it** - -## Command reference - -```bash -browse cloud fetch https://example.com # retrieve a page as markdown -browse cloud search "web scraping tools" # search the web -browse cloud sessions list # list cloud browser sessions -browse cloud projects list # list Browserbase projects -``` - -The [interactive driver mode](https://docs.browserbase.com/integrations/skills/browse-cli) (`browse open`, `browse click`, …) is not supported inside the VM yet ([#1631](https://github.com/rivet-dev/agentos/issues/1631)). For interactive automation, run `browse` inside an external sandbox via [External Sandboxes](/docs/sandboxes). \ No newline at end of file diff --git a/website/public/docs/docs/core.md b/website/public/docs/docs/core.md deleted file mode 100644 index 12e0c91a7b..0000000000 --- a/website/public/docs/docs/core.md +++ /dev/null @@ -1,126 +0,0 @@ -# Direct VM API - -Use the direct AgentOS VM API or layer it into an AgentOS actor. - -`@rivet-dev/agentos` ships both the direct `AgentOs` VM API and the `agentOS()` -actor API. - -## Direct VM vs actor - -| | Direct VM | Actor | -|-|---|---| -| Persistence | In-memory by default (pluggable via [mounts](#mounts)) | Persistent filesystem and sessions | -| Distributed state | Manage yourself | Built-in | -| Stateful VMs | Complex to run yourself | Built into Rivet | -| Sleep/wake | Manual `dispose()` / `create()` | Automatic | -| Events | Direct callbacks | Broadcast to all clients | -| Preview URLs | None | Built-in signed URL server | -| Multiplayer | N/A | Multiple clients per actor | -| Orchestration | N/A | Workflows, queues, cron | -| Agent-to-agent | Custom | Built into [Rivet Actors](/docs/agent-to-agent) | -| Authentication | Set up yourself | [Docs](/docs/authentication) | - -- Use [Rivet Actors](https://rivet.dev/docs/actors) for persistence, - networking, and orchestration. -- Use `AgentOs.create()` for direct VM control in a Node.js process. -- `agentOS()` returns an ordinary TypeScript Rivet actor definition — VM options - plus normal actor state, actions, events, queues, connection types, and - lifecycle hooks (`onBeforeConnect`). -- AgentOS actions/events merge in automatically; their names are reserved. -- The VM is created lazily on the first AgentOS action after wake, disposed on - sleep — so a connection can subscribe before `vmBooted`. -- Creation input flows through `client.vm.create("key", { input })` and reaches - `createState(c, input)` and `onCreate(c, input)`. - -## Install - -```bash -npm install @rivet-dev/agentos -``` - -## Boot a VM - -`AgentOs.create()` boots the VM in-process and returns a handle you call -directly — no actor runtime, no client/server split. - -## Sidecar process - -- Every VM runs inside a **shared sidecar process**, not its own process. -- All VMs default to a single process-global sidecar (the `default` pool); each - extra VM adds only a V8 isolate + its kernel state. -- This keeps per-VM memory in the tens of MB and warm creation in single-digit - ms (see [Performance](/docs/performance)). -- Automatic for `agentOS()`, `AgentOs.create()`, and Rivet Actors. -- Disposing a VM tears down only that VM; the sidecar is reused for the host - process lifetime. -- Advanced: the direct VM API exposes explicit sidecar handles to isolate a - group of VMs in their own process. - -## Filesystem - -## Contexts - -Contexts retain JavaScript/TypeScript or Python globals between attached calls. -Create one explicitly, then pass its `contextId`; unknown IDs fail instead of -silently creating fresh state. A context pins to the first inline language used, -although JavaScript and TypeScript intentionally share one isolate. - -Contexts live for the VM lifetime. In an actor, sleep disposes the VM and its -contexts, so create a context lazily on the first stateful action after wake -instead of persisting and blindly reusing its ID. - -## Processes - -- `process.spawn()` and language `spawn` methods return a numeric `pid`. -- `onProcessOutput(pid, …)` — unified stdout/stderr stream. -- `onProcessExit(pid, …)` — completion. - -## Agent sessions - -- `openSession` negotiates the adapter and resolves without a value. -- Omit `sessionId` → `main`. Call `getSession` only for durable metadata. -- Register `onSessionEvent` **before** prompting for live deltas. -- Native ACP updates and permission request/response share the sequenced - `onSessionEvent` stream. -- Durable entries recover via `readHistory`; ephemeral agent/thought deltas do - not. - -## Networking - -`httpRequest({ port, path, ... })` reaches a server inside the VM and returns a -bounded, serializable response DTO. - -## Cron jobs - -- Run an `"exec"` command or a `"session"` prompt on a schedule. -- Fired jobs surface through `onCronEvent`. - -## Mounts - -- Configure filesystem backends at boot. -- Native mount plugins (host directories, S3, etc.) are passed via `plugin`, - each with an `id` and a `config`. - -## Configuration reference - -- All VM config is a single flat object passed to `AgentOs.create()`. -- The [`agentOS()` actor](/docs/quickstart) accepts the same options and layers - persistence, sleep/wake, and preview URLs on top. - -See [Mounts](#mounts) and [Software](/docs/software). - -### Session events - -- `onSessionEvent` receives a union of exact native ACP `SessionUpdate`, - `RequestPermissionRequest`, and `RequestPermissionResponse` payloads wrapped - with AgentOS durability metadata. -- Register before prompting. -- On reconnect, read durable history after your last sequence and dedup by - `(sessionId, sequence)`. - -### Timeouts and sleep - -- Action timeouts and automatic sleep/wake are [`agentOS()` actor](/docs/quickstart) - features, not the direct VM API. -- A direct VM stays alive until `dispose()`. See - [Persistence & Sleep](/docs/persistence). \ No newline at end of file diff --git a/website/public/docs/docs/crash-course.md b/website/public/docs/docs/crash-course.md deleted file mode 100644 index 448961a525..0000000000 --- a/website/public/docs/docs/crash-course.md +++ /dev/null @@ -1,87 +0,0 @@ -# Crash Course - -Run coding agents inside isolated VMs with full filesystem, process, and network control. - -agentOS is in preview and the API is subject to change. If you run into issues, please [report them on GitHub](https://github.com/rivet-dev/rivet/issues) or [join our Discord](https://rivet.dev/discord). - -## When to Use agentOS - -- **Coding agents**: Run any coding agent with full OS access, file editing, shell execution, and tool use. -- **Automated pipelines**: CI-like workflows where agents clone repos, fix bugs, run tests, and open PRs. -- **Multi-agent systems**: Coordinators dispatching to specialized agents, review pipelines, planning chains. -- **Scheduled maintenance**: Cron-based agents that audit code, update dependencies, or generate reports. -- **Collaborative workspaces**: Multiple users observing and interacting with the same agent session in realtime. - -## Minimal Project - -After the quickstart, customize your agent with the [Registry](/registry). - -## Agents - -### Sessions & Transcripts - -Create agent sessions, send prompts, and stream responses in realtime. Transcripts are persisted automatically across sleep/wake cycles. - -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/sessions)* - -### Approvals - -Approve or deny agent tool use with human-in-the-loop patterns or auto-approve for trusted workloads. - -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/approvals)* - -### Bindings - -Expose your JavaScript functions to agents as CLI commands inside the VM. Each binding group becomes a binary at `/usr/local/bin/agentos-{name}`, and each binding becomes a subcommand with flags auto-generated from its Zod input schema. The server below defines a `weather` binding group with a `forecast` binding; the client opens a session and prompts the agent, which calls the binding itself as a shell command. - -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/bindings) or [Documentation](/docs/bindings)* - -### Agent-to-Agent - -Let one agent call another through a [binding](/docs/bindings). The coder gets a `review` binding it invokes itself, which bridges into the reviewer's isolated VM. - -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/agent-to-agent)* - -### Multiplayer - -Connect multiple clients to the same agent VM. All subscribers see session output, process logs, and shell data in realtime. - -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/multiplayer)* - -### Workflows & Graphs - -Orchestrate multi-step agent tasks with durable workflows that survive crashes and restarts. - -[Documentation](/docs/workflows) - -## Operating System - -### Filesystem - -Read, write, and manage files inside the VM. The `/home/agentos` directory is persisted automatically across sleep/wake cycles. - -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/filesystem)* - -### Processes & Shell - -Execute commands, spawn long-running processes, and open interactive shells. - -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/processes)* - -### Networking & Previews - -Proxy HTTP requests into VMs with `httpRequest`. Create actor-namespaced preview URLs for port forwarding VM services to shareable public URLs. - -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/networking)* - -### Crons & Loops - -Schedule recurring commands and agent sessions with cron expressions. - -*See [Full Example](https://github.com/rivet-dev/agentos/tree/main/examples/crash-course) or [Documentation](/docs/cron)* - -### External Sandboxes - -agentOS uses a hybrid model: agents run in a lightweight VM by default and mount a full sandbox on demand for heavy workloads like browsers, compilation, and desktop automation. Sandboxes are powered by [Sandbox Agent](https://sandboxagent.dev), so you can swap providers without changing agent code. Mount the sandbox as a filesystem and expose its process management as bindings. - -[Documentation](/docs/sandboxes) \ No newline at end of file diff --git a/website/public/docs/docs/cron.md b/website/public/docs/docs/cron.md deleted file mode 100644 index 57c20ed905..0000000000 --- a/website/public/docs/docs/cron.md +++ /dev/null @@ -1,43 +0,0 @@ -# Crons & Loops - -Schedule recurring commands and agent sessions in agentOS VMs. - -Schedule recurring work and long-running agent loops with cron expressions, -running either a shell command (`exec`) or an agent session (`session`), with -overlap modes (`allow`, `skip`, `queue`) and native `cronEvent` streaming to -monitor execution. Cron jobs keep the actor alive while a job runs; the actor -can sleep between executions. - -## Schedule a command - -Run a shell command on a recurring schedule. Pass a custom `id` to make a job easier to manage and cancel later. - -## Schedule an agent session - -Create a recurring agent session that runs a prompt on a schedule. - -## Overlap modes - -Control what happens when a cron job triggers while a previous execution is still running. - -| Mode | Behavior | -|------|----------| -| `"skip"` | Skip this trigger if the previous run is still active | -| `"allow"` | Allow concurrent executions (default) | -| `"queue"` | Queue this trigger and run it after the previous one finishes | - -Prefer `"skip"` for most jobs to avoid unbounded concurrency if a run takes longer than the interval. Use `"queue"` when every trigger must eventually execute. - -## Monitor cron events - -Subscribe with `connection.on("cronEvent", ...)` to track job execution. Event and job timestamps are ISO strings. The callback receives a `CronEvent` directly, with no `{ event }` wrapper. - -Subscribe before scheduling so you do not miss early runs. - -## List and cancel cron jobs - -## Example: Heartbeat pattern - -Schedule a recurring agent session to periodically check on a task. This is the core pattern behind [OpenClaw](https://openclaw.org), where an agent wakes up on a schedule to review progress, take action, and go back to sleep. - -The agent sleeps between executions and only consumes resources when the cron job fires. \ No newline at end of file diff --git a/website/public/docs/docs/custom-software/building-wasm.md b/website/public/docs/docs/custom-software/building-wasm.md deleted file mode 100644 index 563485e0b7..0000000000 --- a/website/public/docs/docs/custom-software/building-wasm.md +++ /dev/null @@ -1,59 +0,0 @@ -# Building Binaries - -Compile WASM command binaries for agentOS from source. - -WASM command packages ship **compiled `.wasm` binaries** in their `bin/` that run inside the VM as guest commands. The binaries are build artifacts and are not checked into git, so to add or change a command you build it from source in the AgentOS repo. - -You only need this to author new commands. To use existing ones, install the published package (e.g. `@agentos-software/ripgrep`) and pass it to `software`. See [using the registry](#using-the-registry) below. - -## Where it lives - -Command packages live under top-level `software/`, while shared build infrastructure lives under `toolchain/`: - -- **`software//native/crates/cmd-/`**: the Rust source for each command — a cargo package named `cmd-` that emits a `` binary. -- **`software//native/c/`**: the C source for C-built package commands. -- **`software//`**: the npm package for each command set (`@agentos-software/`). It exports a `{ packagePath }` descriptor pointing at the packed `dist/package.aospkg`, and declares which binaries it ships in its `agentos-package.json` (`commands`, plus optional `aliases` and `stubs`). - -## Build - -Everything runs through `just` recipes at the AgentOS repo root: - -```bash -just toolchain-build # compile ALL native wasm binaries (slow; once per checkout) -just toolchain-cmd sh # recompile ONE command (cargo package cmd-sh) -just software-build # stage + assemble every software package -just software-build ripgrep # ... or just one -``` - -The native build compiles each command for `wasm32-wasip1` with the pinned **nightly** toolchain from `rust-toolchain.toml` (the build vendors and patches `std` for WASI), optimizes with `wasm-opt`, and drops the binaries in `toolchain/target/wasm32-wasip1/release/commands/`. C-based commands (e.g. `sqlite3`, `unzip`, `wget`, `zip`) compile with a **wasi-sdk** clang toolchain via `make -C toolchain/c`. - -Each package's build then runs the **agentos-toolchain** lifecycle: `agentos-toolchain stage` copies the binaries listed in the package's `agentos-package.json` into its `bin/`, and `agentos-toolchain build` assembles the clean `dist/package/` dir with a `bin` map in its `package.json` and packs it into `dist/package.aospkg` (the `{ packagePath }` target). - -## Add a new command package - -1. Add the command source as `software//native/crates/cmd-/` (cargo package `cmd-`; Rust) or under `software//native/c/` (C). -2. Create `software//` as an `@agentos-software/` npm package that exports a `{ packagePath }` descriptor pointing at `dist/package.aospkg`. -3. Declare the shipped binaries in its `agentos-package.json`: `{ "commands": [""] }` (plus `aliases`/`stubs` if needed). -4. If it belongs in a meta-package (e.g. `common` or `build-essential`), add it there. -5. Verify with `just toolchain-cmd && just software-build ` and `pnpm --filter './software/*' test`. - -## Let an agent build it - -This is a mechanical, well-scoped task, so you can hand it to a coding agent. A prompt like: - -```text -Add a WASM command package for `` to AgentOS: -- put the Rust source at software//native/crates/cmd-/ as a cargo - package named cmd-, -- create software// as an @agentos-software/ npm - package that exports a { packagePath } descriptor and declares the command in - its agentos-package.json, -then run `just toolchain-cmd && just software-build ` -and `pnpm --filter './software/*' test`, and fix any failures. -``` - -## Using the registry - -Install a published package and pass it to `software`. Registry WASM packages are `{ packagePath }` descriptors — import and pass them directly: - -Meta-packages bundle a full set, e.g. `@agentos-software/common` (coreutils, sed, grep, gawk, findutils, diffutils, tar, gzip). Run the commands from the client; see [Processes & Shell](/docs/processes). Browse the full catalog on the [Registry](/registry), and see the package descriptor in [Software Definition](/docs/custom-software/definition). To ship your package to npm or use a local build, see [Publishing Packages](/docs/custom-software/publishing). \ No newline at end of file diff --git a/website/public/docs/docs/custom-software/definition.md b/website/public/docs/docs/custom-software/definition.md deleted file mode 100644 index 94b51898e2..0000000000 --- a/website/public/docs/docs/custom-software/definition.md +++ /dev/null @@ -1,161 +0,0 @@ -# Software Definition - -The software-package definition for custom commands and agents in an agentOS VM: a package is a packed .aospkg (or a package directory), declared with defineSoftware({ packagePath }). - -**Software** is anything you install into a VM — **commands** (executables in a package's `bin/`) or an **agent** (a package that also exposes an ACP session). - -A package is **self-contained**: package it first, then point `defineSoftware()` at it with `{ packagePath }` — the packed `.aospkg` the toolchain emits, or (for local development) the package directory itself. The package's name, optional agent block, and any files/env it provides are authored in an `agentos-package.json` next to your sources; the toolchain compiles that JSON into the `.aospkg`'s embedded manifest at pack time (the JSON itself is never shipped into the VM). Pick the quickstart that matches what you're packaging. - -## Quickstart - -### WebAssembly - -1. **You have** C or Rust source for a command. (Most common commands already ship as `@agentos-software/*` packages you can use directly — compile only new or custom ones.) - -2. **Compile it** to WebAssembly — see [Building Binaries](/docs/custom-software/building-wasm). There's **no `pack` step**: WASM binaries are self-contained, so the compile output is already the package — a `bin/` of `\0asm` files plus a `package.json` for the name/version: - - ``` - my-cmds/ - ├── package.json - └── bin/ - ├── tool-a # \0asm WebAssembly - └── tool-b - ``` - -3. **Define it** — point `defineSoftware()` at that directory: - -4. **Use it** — pass it to a VM; the commands are on `$PATH`: - -### Node.js - -1. **You have** a local project whose `package.json` `bin` names its commands: - - ``` - my-tool/ - ├── package.json # "bin": { "my-tool": "cli.js" } - └── cli.js # #!/usr/bin/env node - ``` - -2. **Package it** — `pack` installs the full dependency closure into a self-contained package directory (a flat `node_modules` plus a `bin` map of real files): - - ```bash - npx @rivet-dev/agentos-toolchain pack ./my-tool - # writes ./my-tool-package/ (override the location with --out ) - # my-tool-package/ - # ├── package.json # "bin": { "my-tool": "node_modules/my-tool/cli.js" } - # └── node_modules/ # flat, self-contained closure - ``` - - Commands come from the package's `package.json` `bin` map — **real files, no symlinks** — so the result ships cleanly as an npm dependency. (The runtime makes the `/opt/agentos/bin` symlinks itself when it mounts the package.) A native `.node` addon is an error (it can't run in V8); re-run with `--prune-native` to drop unreachable ones. - -3. **Define it** — point `defineSoftware()` at the packaged directory: - -4. **Use it** — pass it to a VM; `my-tool` is now on `$PATH`: - -### Agent - -An agent is a Node.js or WASM package (packaged exactly as above) whose `agentos-package.json` carries an **`agent` block** naming a `bin/` command that speaks ACP over stdio. - -1. **You have** an npm package with a `bin/` command that speaks ACP over stdio. - -2. **Package it** — same `pack` as Node.js, with `--agent` naming the ACP entrypoint. That writes the `agent` block into the package's `agentos-package.json`: - - ```bash - npx @rivet-dev/agentos-toolchain pack @scope/my-agent --out ./packages --agent my-agent-acp - # → ./packages/my-agent/current (its agentos-package.json now has the agent block) - ``` - -3. **Define it** — point `defineSoftware()` at the packaged directory; the agent block is already in its `agentos-package.json`: - -4. **Use it** — choose a session ID, then `openSession({ sessionId, agent })` launches the agent by spawning its `acpEntrypoint`: - -## Reference - -### The descriptor - -A software entry is just a pointer to the packed package: - -```ts -defineSoftware({ - packagePath: string, // absolute host path to the packed .aospkg - // (or a package directory, for local development) -}) -``` - -The normal `packagePath` is the `dist/package.aospkg` that `agentos-toolchain build`/`pack` emit — -a single file holding the package manifest, a precomputed mount index, and the package's mount tar. -A directory is accepted for local development; it must contain **only the package** — a -`package.json` with a `bin` map, the runtime files (`bin/`, a flat `node_modules`), and an -`agentos-package.json`. It is mounted read-only, so **don't point it at a source root**: that drags -`src/`, dev `node_modules/`, `tsconfig`, and build caches into the VM. - -`pack` already emits the packed `.aospkg`. For a package you build by hand (e.g. compiled WASM), -run `agentos-toolchain build` to assemble `dist/package/` and pack `dist/package.aospkg`, then -point `packagePath` there — never at the workspace root: - -```ts -const packagePath = resolve(import.meta.dirname, "dist/package.aospkg"); -export default defineSoftware({ packagePath }); -``` - -### `agentos-package.json` - -The package's name, optional agent block, and any files/env it provides are authored in an -`agentos-package.json` at the package root. It is **toolchain input**: at pack time it is compiled -into the `.aospkg`'s embedded manifest (which is what the sidecar reads) and stripped from the -packed files, so the JSON never ships into the VM and the metadata never travels on the wire. For -command/WASM packages it is **generated** for you (name from `package.json`); for agents you -author the `agent` block (or `agentos-toolchain pack --agent ` writes it). - -```json -{ - "name": "my-agent", // → /opt/agentos/ - "agent": { // optional — also exposes an agent session - "acpEntrypoint": "my-agent-acp", // bin/ command that speaks ACP over stdio - "env": { }, // static env for the adapter - "launchArgs": [], - "snapshot": false // SDK snapshot optimization - }, - "provides": { // optional — files + env the package contributes - "env": { "EXAMPLE_HOME": "/opt/agentos/my-agent" }, - "files": [{ "source": "etc/example.conf", "target": "/etc/example.conf" }] - } -} -``` - -- **`name`** — the package name; commands and the package mount under `/opt/agentos/`. -- **`agent.acpEntrypoint`** — the `bin/` command spawned to start a session; speaks ACP over stdio. -- **`agent.env`** — static env vars for the adapter, merged under the user env. Every command is on `$PATH`, so point at one directly, e.g. `{ "PI_ACP_PI_COMMAND": "/opt/agentos/bin/pi" }` so `pi-acp` can spawn the `pi` CLI. -- **`agent.launchArgs`** — extra CLI args prepended when launching the adapter. -- **`agent.snapshot`** (default `false`) — load the SDK [once per sidecar](#sdk-snapshotting--snapshot-safety) via a shared V8 heap snapshot instead of per session. Falls back to per-session loading if the SDK isn't snapshot-safe, so it only affects startup latency. -- **`provides.env`** — env vars merged into the VM's base environment (existing values win — a package never clobbers the user env). -- **`provides.files`** — read-only files overlaid into the VM filesystem. Each `{ source, target }` maps a path **inside the package** to an **absolute VM path**; the sidecar mounts them as zero-copy read-only lower layers (a guest write copies-up, never touching the host). A missing `source` is a fatal packaging error. - -## Advanced - -### Meta-packages - -A software entry may be an **array** of descriptors, so one package can bundle several. Pass arrays directly to `software`: - -```ts -const vm = agentOS({ - software: [pi, buildEssential /* = [coreutils, make, git, curl] */], -}); -``` - -### SDK snapshotting & snapshot-safety - -A V8 heap snapshot freezes the heap *after* the SDK's modules are evaluated, then seeds each new session's isolate from it. This works only if the SDK's **module-init** code (everything that runs at `import`/`require` time) doesn't: - -- Create **native handles** — load a `.node` addon, instantiate WebAssembly, or produce a V8 `External`/`Foreign` at top level. -- Open a **file descriptor, socket, timer, or worker**, or leave a **pending promise**. -- Bake in **non-deterministic or per-session state** — `process.env`, cwd, `Date.now()`, `Math.random()`, a UUID. - -Defer all of the above behind functions or lazy `import()` that run per session. Leave `agent.snapshot: false` for any SDK that can't — the agent still runs, just without the speedup. - -## Next steps - -- [Custom Agents](/docs/agents/custom): the agent-focused guide. -- [Building Binaries](/docs/custom-software/building-wasm): compile WASM commands and use the registry. -- [Packages & command resolution](/docs/architecture/packages-and-command-resolution): how packages mount and resolve. -- [Request Software](https://github.com/rivet-dev/agentos/issues/new/choose): ask for a package you need. \ No newline at end of file diff --git a/website/public/docs/docs/custom-software/publishing.md b/website/public/docs/docs/custom-software/publishing.md deleted file mode 100644 index c4ce140529..0000000000 --- a/website/public/docs/docs/custom-software/publishing.md +++ /dev/null @@ -1,79 +0,0 @@ -# Publishing Packages - -Build, publish, and consume agentOS packages — locally, from npm, or from your own repo. - -agentOS packages — WASM command sets and packed JS agents alike — go through one lifecycle, owned by the **`@rivet-dev/agentos-toolchain`** CLI. This page covers the full flow: building a package, publishing it to npm, and wiring a consumer at either a published version or a local checkout. - -## The lifecycle - -Every package is an npm package whose default export points at a self-contained runtime dir (`dist/package/`) that the sidecar projects under `/opt/agentos//`. The toolchain provides four subcommands: - -| Command | What it does | -|---|---| -| `stage --commands-dir ` | Populate `bin/` from a directory of compiled binaries, per the `commands` / `aliases` / `stubs` lists in the package's `agentos-package.json`. | -| `build` | Assemble `dist/package/` from `bin/` (+ optional `share/`) and pack it into `dist/package.aospkg` — the runtime artifact with the embedded manifest (the `agentos-package.json` is pack-time input, not shipped). | -| `pack` | Build a self-contained node-closure package from an npm package or local dir (JS agents; validates headers, rejects native addons). | -| `publish` | Publish the built package to npm. Dist-tag is **`dev` by default**; the `latest` pointer only moves with an explicit `--latest`. | - -## Building - -In the AgentOS registry, the `just` recipes drive the toolchain (see [Building Binaries](/docs/custom-software/building-wasm)): - -```bash -just toolchain-build # compile the native wasm binaries (once per checkout) -just software-build # stage + assemble every software package -just software-build coreutils # ... or one package -``` - -## Publishing - -Registry packages **version independently** — each package carries its own semver in its `package.json`. Bump and commit the version, then: - -```bash -just registry-publish coreutils # publish under dist-tag `dev` -just registry-publish coreutils my-branch # ... under a custom tag -just registry-publish coreutils latest # DELIBERATE release: moves `latest` -just registry-publish-all # every built software package, tag `dev` -``` - -Consumers installing `@agentos-software/` with no tag resolve `latest`, so `latest` is reserved for deliberate releases — a dev publish can never clobber what users install. - -## Consuming published packages - -In agent-os, the `@agentos-software/*` packages are pinned **per-package** in the workspace catalog. Manage the pins with the `just` recipes (never hand-edit them): - -```bash -just agentos-pkgs-status # current mode + pinned versions -just agentos-pkgs-set-version coreutils 0.3.1 # pin one package -just agentos-pkgs-update # re-pin all from the `latest` dist-tag -just agentos-pkgs-update dev # ... or from another tag -``` - -## Local development - -AgentOS consumes local registry builds by default because the software packages -are pnpm workspace members. Build the native commands with `just toolchain-build` -and assemble packages with `just software-build`; no sibling checkout or -published package is required while iterating. - -Published-version pins exist only in release validation and downstream -consumers. The AgentOS workspace itself stays self-contained. - -## Publishing from your own repo - -The toolchain is not registry-specific — any repo can produce and publish agentOS packages with `npx @rivet-dev/agentos-toolchain`: - -```bash -# a package dir with package.json + agentos-package.json + your compiled binaries -npx @rivet-dev/agentos-toolchain stage --commands-dir ./build/wasm -npx @rivet-dev/agentos-toolchain build -npx @rivet-dev/agentos-toolchain publish --tag dev # or --latest for a release -``` - -For a JS agent, `pack` replaces `stage`/`build`: - -```bash -npx @rivet-dev/agentos-toolchain pack . --out dist/package --agent my-acp-entrypoint -``` - -The published package is a plain npm dependency — consumers import its descriptor and pass it to `software` exactly like the software packages. See [Software Definition](/docs/custom-software/definition) for the descriptor shape. \ No newline at end of file diff --git a/website/public/docs/docs/debugging.md b/website/public/docs/docs/debugging.md deleted file mode 100644 index d1966cf59c..0000000000 --- a/website/public/docs/docs/debugging.md +++ /dev/null @@ -1,57 +0,0 @@ -# Debugging - -Capture agent logs and runtime (sidecar) logs to diagnose sessions, tool calls, and crashes. - -Before reaching for logs, open the [inspector](/docs/inspector): it shows the live transcript, pending permission requests (the most common reason an agent looks stuck), and the process tree. - -Two log streams help diagnose what's happening inside a VM: the **agent's** own output and the **runtime (sidecar)** logs. - -## Agent logs (`onAgentStderr`) - -The coding agent (ACP adapter) runs as a process inside the VM and uses **stdout for the ACP protocol**, so its **stderr** carries the agent's logs, warnings, and crash output — the first place to look when a tool call or session fails mid-turn. Capture it with `onAgentStderr` on the VM: - -It's a VM-level option covering every session's agent process; if omitted, chunks are written to the host `process.stderr` by default. See [Sessions → Agent logs](/docs/sessions#agent-logs). - -## Agent crashes (`onAgentExit`) - -If an adapter exits unexpectedly, the runtime logs the exit, does **not** restart it or replay an uncertain prompt, and fires `onAgentExit`: - -```ts -const agentOs = await AgentOs.create({ - software: [pi], - onAgentExit(event) { - // restart is always "not_attempted". A later explicit prompt restores the - // durable session through resume, load, or bounded transcript continuation. - console.warn(`agent exited (code ${event.exitCode}), restart=${event.restart}`); - }, -}); -``` - -The durable session and committed SQLite history remain available. The crash *reason* is on the adapter's stderr; the exit event reports that the live runtime disappeared. A later explicit prompt performs restoration. See [Sessions](/docs/sessions). - -## Runtime logs (sidecar) - -The agentOS sidecar emits structured **logfmt** logs for request handling, networking, and lifecycle. Configure them with environment variables on the **host process** (the sidecar inherits the host environment): - -| env var | effect | -|---------|--------| -| `AGENTOS_LOG_LEVEL` / `LOG_LEVEL` / `RUST_LOG` | log filter, in that priority. Uses [EnvFilter](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html) syntax, e.g. `debug`, `info`, `agentos_sidecar=debug,info`. Default `info`. | -| `RUST_LOG_FORMAT` | `logfmt` (default) or `text` | -| `AGENTOS_LOG_FILE` | append logs to this file instead of stderr (never stdout, which carries the wire protocol) | -| `RUST_LOG_{SPAN_NAME,SPAN_PATH,TARGET,LOCATION,MODULE_PATH,ANSI_COLOR}` | per-field toggles (`=1` to enable) | - -```bash -AGENTOS_LOG_LEVEL=debug AGENTOS_LOG_FILE=./sidecar.log RUST_LOG_FORMAT=logfmt node app.mjs -``` - -Produces logfmt lines such as: - -```text -ts=2026-… level=info message="ext request received" kind=create_session -ts=2026-… level=info message="ext request handled" kind=create_session elapsed_ms=1798 -ts=2026-… level=debug message="querying: api.anthropic.com. A" -``` - -Most sidecar log activity is on the session/ACP path. A bare `AgentOs.create()` or a single `exec()` emits almost nothing — create a session (and send a prompt) to see request-handling logs. - -Use **agent logs** to see what the agent did (tool calls, model errors), and **runtime logs** to see what the sidecar did around it (request timing, DNS, lifecycle). \ No newline at end of file diff --git a/website/public/docs/docs/deployment.md b/website/public/docs/docs/deployment.md deleted file mode 100644 index dd6e9a2620..0000000000 --- a/website/public/docs/docs/deployment.md +++ /dev/null @@ -1,19 +0,0 @@ -# Deploy - -Choose the right deployment option for agentOS. - -agentOS is powered by [Rivet](https://rivet.dev), an open-source actor platform, and runs as Rivet Actors. Three ways to run it in production: - -- **[Rivet Cloud](https://rivet.dev/cloud)**: fully managed (Rivet Compute, or bring your own cloud). Zero-ops. -- **Self-hosted**: run the open-source Rivet platform on your own infrastructure (Kubernetes, Hetzner, VMs, and more) for full control. -- **[Direct VM API](/docs/core)**: embed `@rivet-dev/agentos` directly in any Node.js backend, no platform required. - -Pick a deploy target below, or see [Rivet's deployment guides](https://rivet.dev/docs/deploy/). - -## Deploy targets - -See the [Rivet deploy docs](https://rivet.dev/docs/deploy/) for the full list. Available targets: - -## Enterprise support - -Enterprise support and managed deployment are available, including dedicated support, custom SLAs, and compliance reviews. [Contact the Rivet team](https://rivet.dev/sales) to discuss your requirements. \ No newline at end of file diff --git a/website/public/docs/docs/embedtest.md b/website/public/docs/docs/embedtest.md deleted file mode 100644 index e117bbab84..0000000000 --- a/website/public/docs/docs/embedtest.md +++ /dev/null @@ -1,10 +0,0 @@ -# Embed Test - -Temporary test of the file-embed mechanism. - -# Embed Test - -This code is embedded from a real example file: - -```ts file="examples/quickstart/hello-world/index.ts" -``` \ No newline at end of file diff --git a/website/public/docs/docs/filesystem.md b/website/public/docs/docs/filesystem.md deleted file mode 100644 index a5bf0343ea..0000000000 --- a/website/public/docs/docs/filesystem.md +++ /dev/null @@ -1,70 +0,0 @@ -# Filesystem - -Read, write, mount, and manage files inside agentOS, all backed by a virtual filesystem isolated from the host disk. - -Each VM has its own filesystem that the agent works in. Guest `fs` calls never touch the host disk, and it persists automatically across sleep/wake with no setup. See [Persistence](/docs/persistence) for the details. - -## Mounts - -Back a guest path with external storage by adding it to the `mounts` config. Each mount takes a `path` and an optional `readOnly` flag, and the guest only ever sees the mounted subtree, never the wider host. - -Project a real host directory into the filesystem, Docker-style. The guest sees only the mounted subtree, never the wider host filesystem. Path-escape attempts (symlinks, `..`, path aliasing) are confined to the mount root. - -Mount an S3 bucket with the built-in `s3` plugin. Pass an optional `prefix` to scope storage to a key path within the bucket, useful for sharing one bucket across multiple agents. - -The backend is a block store, not a one-object-per-file mapping: file contents are split into fixed-size chunks (4 MB by default) stored as individual S3 objects, with a separate metadata layer mapping each file to its chunks. This keeps large files, partial reads and writes, and snapshots efficient without rewriting whole objects. - -The `s3` plugin config also accepts `credentials` (`{ accessKeyId, secretAccessKey }`) and a custom `endpoint` for S3-compatible providers. - -Mount a Google Drive folder with the built-in `google_drive` plugin. - -Use the built-in `memory` plugin for an ephemeral mounted directory in the RivetKit `agentOS()` actor. - -Use `mountFs()` with a serializable, sidecar-owned plugin descriptor. The same descriptor works through Core and RivetKit; the actor persists dynamic descriptors in SQLite and replays them on wake. `mountFs()` resolves only once the mount is visible to guest code, and `unmountFs(path)` removes it. - -The actor's durable root is handled separately: the sidecar connects directly to Rivet's actor SQLite UDS, so root filesystem reads and writes never pass through JavaScript. `listMounts()` returns live sanitized metadata without plugin configuration. - -## File operations - -These operations are primarily what the agent uses inside the VM, and are also available from the client to seed inputs and read results. For large or read-only inputs (a repo, a dataset), a read-only [host mount](#mounts) is faster than copying files in. Programs that need stdin or live output use exec instead (see the [Direct VM API](/docs/core)). - -### Read and write - -### Batch read and write - -### Directories - -### File metadata - -### Move and delete - -## Permissions - -Filesystem access is governed by the VM permission policy. The filesystem scope is granted by default; restrict it by path, for example to deny a sensitive directory: - -```ts -const vm = agentOS({ - permissions: { - fs: { - default: "allow", - rules: [{ mode: "deny", operations: ["*"], paths: ["/home/agentos/secrets/**"] }], - }, - }, -}); -``` - -See [Permissions](/docs/permissions) for the full configuration. - -## Sandboxes - -For heavier workloads, run a full Linux [external sandbox](/docs/sandboxes) alongside the VM and mount its filesystem into agentOS. The agent then reads and writes the sandbox's files through the same `fs` APIs while the sandbox handles execution. - -## Default layout - -With no `mounts` configured, every VM boots an Alpine-based root filesystem with the standard POSIX directories: - -- `/home/agentos`: the agent's home directory (`$HOME`) and default working directory (`pwd`) when spawned, where it reads and writes (mounts land under it, e.g. `/home/agentos/data`). -- `/bin`, `/sbin`, `/usr`: installed commands (common POSIX utilities by default, plus any [software](/docs/software) you add). -- `/etc`, `/lib`, `/opt`, `/root`, `/run`, `/srv`, `/tmp`, `/var`, `/mnt`: standard system paths. - -It is backed by the VM's own filesystem and persisted across sleep/wake. Nothing comes from or touches the host disk. \ No newline at end of file diff --git a/website/public/docs/docs/frameworks/flue.md b/website/public/docs/docs/frameworks/flue.md deleted file mode 100644 index c0c063c32b..0000000000 --- a/website/public/docs/docs/frameworks/flue.md +++ /dev/null @@ -1,75 +0,0 @@ -# Flue - -Use agentOS as the durable sandbox backend for Flue. - -Flue owns the agent runtime and session lifecycle. Rivet maps each agent instance and workflow run to a durable Rivet Actor, while agentOS gives each Flue context an isolated VM with a persistent `/workspace` filesystem. - -[View the complete example →](https://github.com/rivet-dev/agentos/tree/main/examples/flue) - -## Quickstart - -```sh -mkdir my-agent && cd my-agent -npm init -y -npm pkg set type=module - -# Install the Flue packages -npm add "@flue/runtime@npm:@rivet-dev/labs-flue-runtime@1.0.0-beta.9-rivet.2" -npm add --save-dev "@flue/cli@npm:@rivet-dev/labs-flue-cli@1.0.0-beta.9-rivet.2" - -# Install the Rivet packages -npm add @rivet-dev/flue @rivet-dev/agentos @rivet-dev/agentos-flue rivetkit - -# Initialize the project -npx flue init --target node -``` - -- `@flue/cli` and `@flue/runtime`: Build and run the Flue project using Rivet's preview Flue packages. -- `@rivet-dev/flue`: Runs Flue agents and workflows as Rivet Actors. -- `@rivet-dev/agentos` and `@rivet-dev/agentos-flue`: Provide the agentOS VM and connect Flue's sandbox API to it. - -*This uses [Rivet's Flue fork](https://github.com/rivet-dev/flue). We're working to merge its extension APIs upstream so Flue can support actor-model runtimes without a Rivet fork.* - -Create `actors.ts`: - -Update `flue.config.ts`: - -Create `agents/assistant.ts`: - -Set the provider key required by your model, such as `ANTHROPIC_API_KEY`, in `.env`. - -Run the agent: - -```sh -npx flue run assistant --id local \ - --input '{"message":"Write hello from Flue to /workspace/hello.txt, run wc -c /workspace/hello.txt, then read the file back."}' -``` - -Deploy to one of the supported platforms: - -## Runtime model - -agentOS does not support Cloudflare Workers yet. It works with Node.js, Bun, or -Deno on platforms such as Railway, Kubernetes, or Vercel. - -## Default filesystem - -agentOS persists the VM filesystem, including `/workspace`, to Rivet Actor storage by default. Additional mounts can be configured as needed. - -## Configuration - -### Virtual machine - -See the `agentOS()` [configuration reference](/docs/core#configuration-reference) to configure the VM. - -### Flue sandbox - -`agentOSSandbox()` accepts: - -| Option | Required | Description | -| --- | --- | --- | -| `actor` | Yes | Actor registered with `setup()`, such as `vm`. | -| `registry` | Yes | The application registry exported from `actors.ts`. | -| `cwd` | No | Base directory exposed to Flue. Defaults to `/workspace`. | -| `params` | No | Connection parameters forwarded to the actor's `onBeforeConnect` hook. | -| `client` | No | An existing client configured for the same registry. | \ No newline at end of file diff --git a/website/public/docs/docs/frameworks/rivet.md b/website/public/docs/docs/frameworks/rivet.md deleted file mode 100644 index 2d8be76e80..0000000000 --- a/website/public/docs/docs/frameworks/rivet.md +++ /dev/null @@ -1,45 +0,0 @@ -# Rivet - -Run agentOS natively as Rivet Actors. - -Rivet is agentOS's native framework. The `agentOS()` function returns an ordinary [Rivet Actor](https://rivet.dev/docs/actors), so each agentOS VM is a directly addressable actor with its own durable filesystem, state, and session history—no adapter layer required. - -[View the complete example →](https://github.com/rivet-dev/agentos/tree/main/examples/quickstart-app) - -## Quickstart - -```sh -mkdir my-agent && cd my-agent -npm init -y -npm pkg set type=module -npm add @rivet-dev/agentos @agentos-software/pi -npm add --save-dev tsx typescript -``` - -Create `server.ts`. The `agentOS()` call returns a normal Rivet Actor definition, and `setup()` registers it with the Rivet runtime: - -Create `client.ts` to address an actor by name, subscribe to its events, open a session, and send a prompt: - -Start the actor, then run the client in a second terminal with the provider key required by your model: - -```sh -# Terminal 1 -npx tsx server.ts - -# Terminal 2 -ANTHROPIC_API_KEY=... npx tsx client.ts -``` - -Because an agentOS VM is a Rivet Actor, you can compose it with Rivet's orchestration primitives: - -- **[Durable workflows](/docs/workflows)** — Run multi-step agent tasks that retry and resume after crashes. -- **[Multiplayer agents](/docs/multiplayer)** — Stream agent output to multiple connected clients in real time. -- **[Agent-to-agent systems](/docs/agent-to-agent)** — Connect isolated agents through typed bindings and durable pipelines. -- **[Scheduled agents](/docs/cron)** — Run commands and agent sessions on timers or cron schedules. -- **[Human-in-the-loop flows](/docs/approvals)** — Pause for tool approval and resume from durable event history. - -Deploy to one of the supported platforms: - -## Learn more - -See the [agentOS quickstart](/docs/quickstart) for VM configuration and the [Rivet Actor documentation](https://rivet.dev/docs/actors) for state, actions, events, queues, workflows, and deployment. \ No newline at end of file diff --git a/website/public/docs/docs/frameworks/vercel-eve.md b/website/public/docs/docs/frameworks/vercel-eve.md deleted file mode 100644 index a7381bbc31..0000000000 --- a/website/public/docs/docs/frameworks/vercel-eve.md +++ /dev/null @@ -1,105 +0,0 @@ -# Vercel Eve - -Run Vercel Eve with agentOS and Rivet World. - -Eve owns the agent runtime and session lifecycle. agentOS maps every sandbox session to an isolated VM actor with a durable `/workspace` filesystem, while Rivet World runs Eve workflows on Rivet Actors. - -[View the complete example →](https://github.com/rivet-dev/agentos/tree/main/examples/vercel-eve) - -## Quickstart - -```sh -npx eve@latest init my-agent -cd my-agent -``` - -```sh -npm add @rivet-dev/agentos @rivet-dev/agentos-eve @rivet-dev/vercel-world -``` - -- `@rivet-dev/agentos` and `@rivet-dev/agentos-eve`: Provide the agentOS VM and connect Eve's sandbox API to it. -- `@rivet-dev/vercel-world`: Runs Eve workflows on [Rivet World](https://workflow-sdk.dev/worlds). - -Update `agent/agent.ts`: - -Rivet World lets you run Eve on top of Rivet. - -Add the World module import to `package.json`: - -```json title="package.json" -{ - "imports": { - "#world": "./world.ts" - } -} -``` - -Create `world.ts`: - -The first World operation starts this registry and waits for the Rivet envoy to -be ready. - -Create `actors.ts`: - -Create `agent/sandbox.ts`: - -Install the Vercel CLI, then link Eve once so it can call your configured model: - -```sh -npm install --global vercel@latest -npx eve link -``` - -Then run the agent: - -```sh -npx eve dev -``` - -By default, agentOS runs locally with `npx rivetkit dev` — no infrastructure needed. To run in production, deploy to any of these targets: - -See [Deployment](/docs/deployment) for managed, self-hosted, and agentOS Core options. - -## Default Filesystem - -agentOS persists the VM filesystem, including `/workspace`, to Rivet Actor storage by default. Additional mounts can be configured as needed. - -## Configuration - -### Virtual Machine - -See the `agentOS()` [configuration reference](/docs/core#configuration-reference) to configure the VM. - -### Eve Sandbox Backend - -`agentOSBackend()` accepts: - -| Option | Required | Description | -| --- | --- | --- | -| `actor` | Yes | Actor registered with `setup()`, such as `vm`. | -| `registry` | Yes | The application registry containing that actor. It is started lazily and shared by Eve sessions. | -| `client` | No | An existing client configured for the same registry. | - -### Rivet World - -Rivet World stores Eve workflow runs in Rivet Actors so they resume instead of restarting. - -[Read the Rivet World documentation →](https://rivet.dev/docs/integrations/vercel-workflows) - -## Advanced - -### agentOS Core Backend - -Use `agentOSCoreBackend()` when Eve should create agentOS Core VMs directly without Rivet Actor orchestration. The `create` callback owns the complete VM configuration: - -```sh -pnpm add @rivet-dev/agentos-core -``` - -When using agentOS Core instead of regular agentOS, you lose: - -- **Durable filesystem and session history.** Core's root filesystem is ephemeral by default, so you must provide your own persistent mount at `/workspace`. -- **Stable per-session actor identity.** Core cannot reconnect to the same VM across Eve process restarts. -- **Automatic sleep and wake.** The VM lives inside Eve's short-lived server process instead staying awake for a given grace period. `shutdown()` disposes it. - -Use Core only when your application owns equivalent persistence and lifecycle management. \ No newline at end of file diff --git a/website/public/docs/docs/inspector.md b/website/public/docs/docs/inspector.md deleted file mode 100644 index c9b8c49f0b..0000000000 --- a/website/public/docs/docs/inspector.md +++ /dev/null @@ -1,55 +0,0 @@ -# Inspector - -Watch and drive a live VM from the Rivet dashboard: transcript, filesystem, and system tabs. - -Every agentOS actor ships a set of tabs for the Rivet dashboard's actor inspector. Open a running VM and you can read the agent's transcript, send it prompts, answer permission requests, browse the filesystem, and watch its processes. Nothing to configure: the tabs register automatically when you use `agentOS()`. - -## Open the inspector - -Any server with an agentOS actor gets the inspector for free: - -Start the server, open the dashboard, and click into the actor: - -```bash -npx tsx server.ts -# then open http://localhost:6420/ui -``` - -The stock rivetkit tabs (state, connections, console) are replaced by the agentOS tabs. The tab assets are served by your server process through the actor gateway, so the same tabs work wherever the dashboard can reach the actor, locally or deployed. - -## Transcript - -A chat view of every session on the VM: user and agent messages, thinking, tool calls with their inputs and outputs, and the agent's plan. Plumbing events collapse into expandable rows so they never dominate the pane. - -The composer at the bottom drives the agent directly: pick an agent type, set per-session env vars (such as an API key, which stays in your browser), and send prompts. This is the same data and the same actions your code uses via `openSession`, `prompt`, and the `sessionEvent` stream. See [Sessions](/docs/sessions). - -## Approvals - -When an agent asks for permission, a banner appears above every tab with the request and its reply options. The agent's turn blocks until someone answers, so an unanswered request is the most common reason an agent looks stuck. See [Approvals](/docs/approvals). - -## Filesystem - -Browse the VM's filesystem and read files, the same view your code gets through the fs API. Note that the root filesystem is in-memory; files outside persisted mounts do not survive VM restarts. See [Filesystem](/docs/filesystem). - -## System - -Everything about the machine itself, in one scroll view. When the VM is asleep, the tab says so instead of waking it. - -- **Processes** — the full kernel process tree, refreshed live. Select a process for its details (ppid, cwd, driver, exit code), stop or kill it, and watch a live output tail for processes spawned through the SDK. See [Processes & Shell](/docs/processes). -- **Software** — installed software bundles with their commands. See [Software](/docs/software). -- **Mounts** — the configured mounts with their access modes. See [Sandbox Mounting](/docs/sandbox). -- **Preview links** — create a signed URL to an HTTP server on a port inside the VM. See [Networking](/docs/networking). - -Actor identity and lifecycle controls (id, key, runner, sleep, destroy) live in the dashboard's own Metadata tab; the System tab covers only what is inside the VM. - -## VM status badges - -When something needs attention, compact badges appear in each tab's own toolbar: a state note when the VM is asleep, shut down after an error, or the sidecar is unhealthy, and an amber warnings pill (resource-limit warnings and agent crash exits, expandable into a panel). While the VM is simply healthy nothing shows; the live session count sits in the Transcript tab's session list. The health poll behind the badges never wakes a sleeping VM, so leaving the inspector open never boots anything. The warnings are the same data your code receives through `onLimitWarning` and `onAgentExit`; see [Resource Limits](/docs/resource-limits) and [Debugging](/docs/debugging). - -## Access control - -The dashboard holds a single per-actor inspector token, and that token authorizes every action the tabs can perform, including sending prompts, answering permission requests, writing files, and killing processes. There is no per-action scoping: treat dashboard access to an actor as operator access to its VM. - -## How it relates to your code - -The inspector is a window onto the same actor actions the SDK exposes; nothing it shows is inspector-only state. Every tab maps to an API you can call from your own code, so anything you find while inspecting (a session to resume, a file to read, a process to kill) is one SDK call away. \ No newline at end of file diff --git a/website/public/docs/docs/javascript-compatibility.md b/website/public/docs/docs/javascript-compatibility.md deleted file mode 100644 index 3be45e0f5e..0000000000 --- a/website/public/docs/docs/javascript-compatibility.md +++ /dev/null @@ -1,71 +0,0 @@ -# Node.js Compatibility - -Node.js builtins available to JavaScript running inside AgentOS. - -Guest JavaScript never touches the host Node.js runtime. - -- Every `node:` `import`/`require` resolves to a VM-backed bridge or an - in-isolate implementation. -- Unknown or denied modules fail explicitly with `ERR_ACCESS_DENIED`. -- The guest reports Node.js `v22.0.0` via `process.version`. - -How builtins are backed: - -- **VM-backed** — routes through the VM filesystem, sockets, processes, DNS, or - entropy. -- **In-isolate** — pure JavaScript running inside V8; no host access. -- **Denied** — importing throws `ERR_ACCESS_DENIED`. - -A guest never falls through to a real host builtin. Anything not bridged -or implemented in the isolate is denied. - -## VM-backed builtins - -| Module | Backed by | -| --- | --- | -| `fs`, `fs/promises` | VM filesystem: fds, streams, metadata, symlinks, polling watchers. | -| `child_process` | VM process table. `spawn`, `exec`, `execFile`, sync variants. | -| `net`, `dgram` | VM TCP, Unix-socket, and UDP tables. | -| `dns`, `dns/promises` | VM DNS resolver. | -| `http`, `https`, `http2`, `tls` | VM socket/TLS paths: clients, servers, pooling. | -| `os` | VM-scoped platform, arch, hostname, CPU, memory, user. | -| `crypto` | Entropy, hashes, HMAC, ciphers, scrypt, UUIDs, WebCrypto. | -| `process` | VM env, cwd, signals, timers, stdio, umask. | -| `module` | `createRequire`, builtin resolution, basic `Module` compat. | -| `console` | Bounded formatting, guest stdout/stderr. | -| `readline`, `sqlite`, `tty` | VM-backed compatibility surfaces. | -| `timers`, `timers/promises` | Timeout, interval, immediate, promise variants. | -| `stream/web`, `stream/consumers`, `stream/promises` | Web Streams + stream helpers. | - -- Network builtins obey the VM [permission policy](/docs/permissions). -- Network access is **denied until granted** by the VM creator. - -## In-isolate builtins - -- Full: `path`, `buffer`, `events`, `stream`, `util`, `assert`, `url`, - `querystring`, `string_decoder`, `zlib`, `punycode`, `constants`, `sys`. - Default and named ESM imports supported. -- Feature-detection shims: `async_hooks`, `diagnostics_channel`, `perf_hooks`, - `worker_threads`, `vm`, `v8`. `worker_threads` does **not** create real - worker threads. - -## Denied builtins - -`cluster`, `domain`, `inspector`, `repl`, `trace_events`, `wasi`. - -## Global APIs - -- Modern web globals: `fetch`, `Headers`, `Request`, `Response`, - `TextEncoder`/`TextDecoder`, `Buffer`, URL APIs, `Blob`, `File`, `FormData`, - abort APIs, `structuredClone`, `performance`, WebAssembly. -- `fetch()` uses VM sockets and follows the same policy as `http`/`net`. - -## Modules and output - -- ESM and CommonJS both use the VM filesystem and normal `node_modules` - resolution. -- Console/stream output flows through the bounded process-output path — see - [Processes & Shells](/docs/processes). - -Back to the [JavaScript guide](/docs/javascript) for TypeScript, packages, -files, processes, networking, bindings, permissions, and limits. \ No newline at end of file diff --git a/website/public/docs/docs/javascript.md b/website/public/docs/docs/javascript.md deleted file mode 100644 index e317c89e37..0000000000 --- a/website/public/docs/docs/javascript.md +++ /dev/null @@ -1,84 +0,0 @@ -# Node.js - -Execute JavaScript and TypeScript, install npm dependencies, and manage execution lifecycles in agentOS. - -agentOS runs JavaScript and TypeScript on native V8 inside the VM, backed by a -real Node.js surface: `node:fs`, `node:child_process`, sockets, and npm. - -Letting an agent write code instead of chaining one tool call per step is called -[Code Mode](https://blog.cloudflare.com/code-mode/). It has a few advantages over -driving [Bash](/docs/bash): - -- **Fewer tokens**: Ten chained operations cost one round trip, not ten. -- **Type checking**: Validate generated TypeScript before you run it. -- **Real data processing**: `map` and `filter` instead of `jq` and `awk`. -- **Parallelism**: `Promise.all` instead of shell job control. - -## Evaluate an expression - -`evaluate()` returns a JSON-serializable value. - -Returning `undefined`, a function, a symbol, or a circular value fails with -`evaluation_serialization_failed` rather than silently losing the value. - -## Execute code - -`execute()` runs source and captures its output instead of returning a value. - -Executions are ephemeral, so capture stdio only when you want it — `"stderr"` for -diagnostics, `"all"` for both streams. `onStdout`/`onStderr` stream live and work -independently of capture. - -## Pass data into code - -`inputs` hands host values to the guest as real objects, so data never gets -interpolated into source. - -## Keep state between calls - -Pass a `contextId` to keep globals, imports, and modules alive across calls in -one retained V8 isolate. - -A context runs one operation at a time — reusing a busy `contextId` fails -immediately. Files, npm, Bash, and type checks may pass the same id, but they run -in fresh processes and never touch retained memory. - -Contexts live for the VM lifetime. They do not survive actor sleep/wake, because -the VM is disposed; create them lazily on the first stateful use after wake. - -## Type check before running - -Executing TypeScript transpiles it without a semantic check, so validate the -agent's generated code explicitly. - -## Install npm packages - -Installs modify the VM-wide filesystem, so a package installed once is importable -by every later execution in that VM, in any language. Only one npm/Python -mutation runs at a time per VM; a concurrent install fails with `execution_busy`. - -## Background processes and web servers - -`spawn` starts a long-lived process and returns a `pid`. From there you get -stdin, output, signals, and waiting. - -Spawned processes always start with fresh state, so they take no `contextId`. - -## A full Linux environment underneath - -There is a real Linux environment behind all of this, shared by every language. -Files and installed packages are immediately visible to Bash, Python, agents, and -other executions. - -See [Filesystem](/docs/filesystem), [Processes & Shells](/docs/processes), and -[Networking & Previews](/docs/networking). - -## Bindings - -Guest code invokes [bindings](/docs/bindings) as ordinary typed commands, so host -credentials stay outside the VM. - -## Permissions, limits, and timeouts - -Every operation inherits the VM [permission policy](/docs/permissions) and -[resource limits](/docs/resource-limits). \ No newline at end of file diff --git a/website/public/docs/docs/limitations.md b/website/public/docs/docs/limitations.md deleted file mode 100644 index 3bfb19d393..0000000000 --- a/website/public/docs/docs/limitations.md +++ /dev/null @@ -1,31 +0,0 @@ -# Limitations - -What the agentOS VM does not support, and how to work around it. - -agentOS is a Linux environment with a POSIX-compliant virtual kernel. It handles most agent workloads (coding, scripting, file I/O, networking) with near-zero overhead. - -## Sandbox mounting - -When a workload needs a full Linux OS, agents can escalate to a full sandbox on demand without changing code. The [external sandbox](/docs/sandboxes) extension mounts the sandbox as a filesystem and lets you execute commands on it, like mounting a hard drive on your own machine. Files written in the VM are available in the sandbox and vice versa. - -See [agentOS vs Sandbox](/docs/versus-sandbox) for a detailed comparison. - -## Limitations - -### Software registry - -agentOS uses its own [software registry](/registry) of popular tools cross-compiled for the runtime. You cannot download and install arbitrary binaries (for example via `curl` or `apt`), and standard Linux package managers (`apt`, `yum`) are not available since agentOS runs a streamlined Linux environment rather than a full distribution. Native binaries that are not yet available in the registry (such as Go, Rust, or C++ toolchains) require a full [external sandbox](/docs/sandboxes). - -See [Software](/docs/software) for how to install and configure available packages. - -### Lightweight Linux kernel - -agentOS provides a POSIX-compliant virtual Linux kernel with full filesystem operations, networking, and process management. It implements a focused subset of the kernel surface, so a few Linux-specific features are not available: - -- Kernel modules and eBPF -- Container runtimes (e.g. Docker) -- File watching (`inotify`, `fs.watch`) - -### No hardware access - -The VM has no access to GPUs, USB devices, or other hardware. \ No newline at end of file diff --git a/website/public/docs/docs/models-and-credentials.md b/website/public/docs/docs/models-and-credentials.md deleted file mode 100644 index ed16f98bdd..0000000000 --- a/website/public/docs/docs/models-and-credentials.md +++ /dev/null @@ -1,31 +0,0 @@ -# Models & Credentials - -Choose agent models and pass provider credentials to sessions securely. - -- Choose the model through your **agent adapter**. -- Pass provider credentials from trusted server code. -- Credentials are injected at session creation and can be isolated per tenant. -- The VM does **not** inherit the host `process.env` — keys must be passed - explicitly. - -## Passing API keys - -Pass LLM provider keys via the `env` option on `openSession`. - -## Per-tenant credentials - -- Key `getOrCreate` on the tenant id → isolated VM per tenant. -- Look up the tenant's key on the server, inject via session `env`. -- Keys stay on the server and never reach the client, and one tenant's key - never reaches another. - -Declare the agent software on the server: - -Resolve each tenant's key and pass it at session creation: - -## Models - -- Model selection belongs to the configured agent adapter. -- AgentOS forwards the session environment and preserves the agent's native - model behavior — no second model-selection layer. -- See your [agent](/docs/agents/pi) page for supported models and providers. \ No newline at end of file diff --git a/website/public/docs/docs/multiplayer.md b/website/public/docs/docs/multiplayer.md deleted file mode 100644 index ccf4024674..0000000000 --- a/website/public/docs/docs/multiplayer.md +++ /dev/null @@ -1,9 +0,0 @@ -# Multiplayer - -Connect multiple clients to the same agentOS actor for collaborative agent workflows. - -Connect multiple clients to the same agentOS actor so all subscribers receive broadcasted session output, process logs, and shell data, enabling collaborative patterns where one user prompts and others observe. - -## Multiple clients observing a session - -All clients connected to the same actor receive broadcasted events. This enables building collaborative UIs where multiple users watch an agent work. \ No newline at end of file diff --git a/website/public/docs/docs/networking.md b/website/public/docs/docs/networking.md deleted file mode 100644 index e015ee03bd..0000000000 --- a/website/public/docs/docs/networking.md +++ /dev/null @@ -1,42 +0,0 @@ -# Networking & Previews - -Proxy HTTP requests into agentOS VMs and create shareable preview URLs. - -Proxy buffered HTTP requests into VM services with `httpRequest` and create time-limited, actor-only preview URLs (with configurable expiration, revocation, and CORS), all carried over one transport (the kernel socket table) that is loopback-only by default under a three-layer confinement model. - -## Run an HTTP server in the VM - -Guest code runs a normal Node HTTP server: it binds a loopback port inside the VM exactly like any Node process. Write the server file and spawn it. - -## Fetch from a VM service - -With the HTTP server running in the VM (above), send requests to it with `httpRequest`, including custom methods, headers, and body. - -## Preview URLs - -Preview URLs are port forwarding for VM services: a time-limited, public URL that proxies HTTP to a port inside the VM, for browser or external access (use `httpRequest` for server-to-server). Preview creation is intentionally actor-only through the native `createPreviewUrl` and `expirePreviewUrl` actions; tokens survive sleep/wake and CORS is enabled. See [Security](/docs/security-model) for details. - -### Create a preview URL - -Token lifetimes are configured under the `preview` key: - -### Revoke a preview URL - -Mint short-lived preview tokens so access expires automatically; the lifetime is capped by `preview.maxExpiresInSeconds`. - -## Permissions - -Network access is governed by the VM permission policy. By default the guest cannot reach the network; grant it, or allow only specific destinations: - -```ts -const vm = agentOS({ - permissions: { - network: { - default: "deny", - rules: [{ mode: "allow", operations: ["*"], patterns: ["api.example.com"] }], - }, - }, -}); -``` - -See [Permissions](/docs/permissions) for the full configuration. \ No newline at end of file diff --git a/website/public/docs/docs/performance.md b/website/public/docs/docs/performance.md deleted file mode 100644 index f94537aa5f..0000000000 --- a/website/public/docs/docs/performance.md +++ /dev/null @@ -1,193 +0,0 @@ -# Performance - -AgentOS latency, memory, cost, and benchmark methodology. - -Benchmark figures shown on the agentOS marketing page, computed from the same -data source. Use the methodology below to measure your own workload and -hardware. - -## Cold start - -Time from requesting an execution to first code running. Measured with the sleep -workload (minimal VM, idle Node.js process). Baseline: **E2B**, fastest -mainstream sandbox as of March 30, 2026. See -[ComputeSDK benchmarks](https://www.computesdk.com/benchmarks/). - -| Metric | agentOS | Fastest sandbox (E2B) | -|---|--:|--:| -| Cold start p50 | 4.8 ms | 440 ms | -| Cold start p95 | 5.6 ms | 950 ms | -| Cold start p99 | 6.1 ms | 3,150 ms | - -## Memory per instance - -Measured via staircase benchmarking: - -1. **Warmup** — a throwaway VM is created and destroyed to pay one-time costs - (module cache, JIT) amortized away in real deployments. -2. **Baseline** — GC forced twice (`--expose-gc`), then RSS sampled across the - whole process tree via `/proc/[pid]/statm` (captures child V8 isolate - processes `process.memoryUsage().rss` would miss). -3. **Staircase** — add VMs one at a time; after each settles, force GC and - resample. Delta = incremental cost of that VM. -4. **Average** — per-VM cost is the mean of step deltas. -5. **Teardown** — dispose all VMs, record reclaimed RSS. - -RSS includes thread stacks and OS-mapped pages beyond the VM, so the reported -figure is an **upper bound**. Baseline: **Daytona**, cheapest mainstream -sandbox as of March 30, 2026 (1 vCPU + 1 GiB). - -### Full coding agent - -Pi session with MCP servers and mounted filesystems. - -| Metric | agentOS | Cheapest sandbox (Daytona) | -|---|--:|--:| -| Memory per instance | ~131 MB | ~1024 MB | - -### Simple shell command - -| Metric | agentOS | Cheapest sandbox (Daytona) | -|---|--:|--:| -| Memory per instance | ~22 MB | ~1024 MB | - -## Cost per execution-second - -- Assumes one agent per sandbox (isolation) and 70% host utilization (standard - HPA threshold). -- Formula: `server cost per second / concurrent executions per server`, where - `concurrent = floor(server RAM / agent memory) × 0.7`. -- Baseline: **Daytona** at $0.0504/vCPU-h + $0.0162/GiB-h, 1 vCPU + 1 GiB min. - Source: [daytona.io/pricing](https://www.daytona.io/pricing). - -### Full coding agent - -| Host tier | agentOS | Cheapest sandbox | Difference | -|---|--:|--:|--:| -| AWS ARM | $0.00000058/s | $0.000018/s | 32x cheaper | -| AWS x86 | $0.00000072/s | $0.000018/s | 26x cheaper | -| Hetzner ARM | $0.000000066/s | $0.000018/s | 281x cheaper | -| Hetzner x86 | $0.00000011/s | $0.000018/s | 171x cheaper | - -### Simple shell command - -| Host tier | agentOS | Cheapest sandbox | Difference | -|---|--:|--:|--:| -| AWS ARM | $0.000000073/s | $0.000018/s | 254x cheaper | -| AWS x86 | $0.000000090/s | $0.000018/s | 205x cheaper | -| Hetzner ARM | $0.000000011/s | $0.000018/s | 1738x cheaper | -| Hetzner x86 | $0.000000017/s | $0.000018/s | 1061x cheaper | - -## Evaluating your own cost - -- agentOS runs on hardware you provision, not per-VM-second billing. -- Estimate: instance cost per second ÷ concurrent VMs it holds with realistic - memory + utilization headroom. -- A VM per task/tenant → strongest isolation; safely reusing a VM for trusted - sequential work amortizes boot + filesystem setup. -- Small short executions benefit most from dense packing; heavy long-lived work - depends more on hardware choice and avoiding per-sandbox minimums. - -Provider prices, instance prices, and workload memory change. Measure -on your target hardware before quoting a cost ratio. - -## Test environment - -| Component | Details | -|---|---| -| CPU | 12th Gen Intel i7-12700KF, 12 cores / 20 threads @ 3.7 GHz, 25 MB cache | -| RAM | 2× 32 GB DDR4 @ 2400 MT/s | -| Node.js | v24.13.0 | -| OS | Linux 6.1.0 (Debian), x86_64 | - -## Sandbox baselines - -| Comparison | Provider | Why | -|---|---|---| -| Cold start | E2B | Fastest mainstream sandbox on [ComputeSDK](https://www.computesdk.com/benchmarks/) as of March 30, 2026 | -| Memory and cost | Daytona | Cheapest mainstream sandbox as of March 30, 2026 ($0.0504/vCPU-h + $0.0162/GiB-h) | - -Self-hosted tiers: AWS t4g.micro (ARM, $0.0084/h, 1 GiB), AWS t3.micro (x86, -$0.0104/h, 1 GiB), Hetzner CAX11 (ARM, €3.29/mo, 4 GiB), Hetzner CX22 (x86, -€5.39/mo, 4 GiB). On-demand pricing. - -## Reproducing - -Benchmarks live in the -[agent-os repository](https://github.com/rivet-dev/agentos) under -`scripts/benchmarks/`. - -**Prerequisites:** - -- Node.js (see `.nvmrc`) and `pnpm`; `pnpm install`. -- A Rust toolchain (`cargo`) — benchmarks build and run the native release - sidecar. -- An **idle machine** — cold-start tails are sensitive to background CPU/GC - jitter. - -**Run everything** (from repo root): - -```sh -./scripts/benchmarks/run-benchmarks.sh -``` - -Builds the TS packages + an **optimized release sidecar**, points the SDK at it -via `AGENT_OS_SIDECAR_BIN`, and writes one JSON per benchmark to -`scripts/benchmarks/results/`: - -| Result file | Feeds marketing input | -|---|---| -| `coldstart-sleep.json` | `COLDSTART_P50/P95/P99_MS` | -| `memory-sleep.json` | `MEMORY_SHELL_MB` (`result.avgPerVmRssBytes / 1024²`) | -| `memory-pi-session.json` | `MEMORY_AGENT_MB` (`result.avgPerVmRssBytes / 1024²`) | - -Copy those into `website/src/data/bench.ts`; every figure recomputes from them. - -**Run a single benchmark** — build first (`pnpm build` and -`cargo build --release -p agent-os-sidecar`), then: - -```sh -export AGENT_OS_SIDECAR_BIN="$PWD/target/release/agent-os-sidecar" - -# Cold start (sleep workload) -pnpm exec tsx scripts/benchmarks/coldstart.bench.ts --workload=sleep --iterations=2000 - -# Memory — simple shell command -pnpm exec tsx --expose-gc scripts/benchmarks/memory.bench.ts --workload=sleep --count=20 - -# Memory — full coding agent -pnpm exec tsx --expose-gc scripts/benchmarks/memory.bench.ts --workload=pi-session --count=10 -``` - -JSON → stdout; human-readable table + progress → stderr. - -**Sample sizes** — percentiles are nearest-rank -(`sorted[ceil(p/100 · n) − 1]`). Too few samples makes the tail meaningless -(at `n = 30`, p99 is literally the single slowest run): - -| Statistic | Minimum iterations | -|---|--:| -| p50 (median) | ~30 | -| p95 | ~200 | -| p99 | ~1,000 | - -- `run-benchmarks.sh` uses `--iterations=2000` for cold start so p95/p99 are - trustworthy. -- Memory per VM is a low-variance mean of step deltas, so `--count=20` (shell) / - `--count=10` (agent) suffices. - -> The `pi-session` memory workload needs a working in-VM agent runtime. Where -> unavailable it fails its process check instead of reporting a number. - -**Methodology:** - -- Each benchmark **creates the sidecar once** (`AgentOs.createSidecar()`) and - leases all VMs from it — VMs are incremental tenants of one shared process, so - figures measure the marginal cost of a VM, not a fresh process. - (`AgentOs.create()` with no `sidecar` option already uses the shared - `default`-pool sidecar — the default everywhere, including RivetKit actors.) -- Before any measured iteration, a **cold run** (throwaway VM, created, started, - snapshotted for cold start) pays one-time spawn + bootstrap, so numbers - reflect warm steady-state per-VM cost. -- The release sidecar is required — a debug build is several times slower and - inflates numbers. \ No newline at end of file diff --git a/website/public/docs/docs/permissions.md b/website/public/docs/docs/permissions.md deleted file mode 100644 index d4ccd0df6e..0000000000 --- a/website/public/docs/docs/permissions.md +++ /dev/null @@ -1,86 +0,0 @@ -# Permissions - -The per-scope kernel permission policy that gates every guest syscall in the sandbox. - -The sandbox permission policy is the kernel-level enforcement layer. Every guest syscall the agent's sandboxed code makes is checked against a per-scope policy before any host resource is touched. - -- **Six scopes**, configured independently: `fs`, `network`, `childProcess`, `process`, `env`, `binding`. -- **Each scope** is a mode (`"allow"` or `"deny"`), or a rule set. -- **A denied operation** is rejected with `EACCES` before any host resource is touched. -- **Merged over a secure default**, so partial policies work. - -For the higher-level agent tool-approval layer (human-in-the-loop, auto-approve), see [Approvals](/docs/approvals). - -## Defaults and merge semantics - -The sandbox is deny-by-default for outward-facing capabilities. When you pass no policy, this baseline applies: - -```ts -{ - fs: "allow", // virtualized in-memory filesystem only - childProcess: "allow", - process: "allow", - env: "allow", - network: "deny", // no network egress until you opt in -} -``` - -- `fs`/`childProcess`/`process`/`env` are allowed because they are fully virtualized (the guest sees only the VM, never the host) and are required to run a program at all. -- `network` is denied: guest code cannot reach the network until you opt in. -- Your policy is merged **over** this baseline. Omitted scopes keep their default; they are **not** denied. So `{ network: "allow" }` grants the network while keeping the execution essentials. - -## Permission scopes - -| Scope | Controls | Default | -|---|---|---| -| `fs` | Filesystem reads, writes, and metadata operations | `allow` | -| `network` | Outbound connections: `fetch`, HTTP, DNS, and inbound `listen` | `deny` | -| `childProcess` | Spawning child processes | `allow` | -| `process` | Process-control operations | `allow` | -| `env` | Environment variable access | `allow` | -| `binding` | Invoking bindings registered with the runtime | `deny`* | - -\* The `binding` scope is auto-granted to `allow` when you register bindings and set no `binding` policy of your own. Pass a `binding` policy to gate individual bindings. - -## Bind a policy to the VM - -A policy is a plain object keyed by scope. Pass it as `permissions` to `agentOS(...)` and it gates every guest syscall on that VM. - -## Grant or deny a whole scope - -The simplest value for a scope is a single mode string. `"allow"` permits every operation in the scope; `"deny"` rejects every one with `EACCES`. Omitted scopes keep their secure default, so you only list what you want to change. - -```ts -const permissions = { - network: "allow", // turn on network egress - fs: "deny", // turn off all filesystem access -}; -``` - -There is no typed `"ask"` mode. Interactive, human-in-the-loop approval lives in the higher-level [Approvals](/docs/approvals) layer, not the kernel policy. To block at the kernel level, use `"deny"`. - -## Allow only specific filesystem paths - -For finer control, a scope can be a rule set instead of a bare mode: a `default` mode plus an ordered list of `rules`. The `fs` scope matches by `paths` (filesystem globs). Each rule names its `operations` (`read`, `write`, `stat`, `readdir`, `create_dir`, `rm`, `rename`, `symlink`, `readlink`, `chmod`, `truncate`, `mount_sensitive`, or `["*"]` for all). Last matching rule wins; if no rule matches, `default` applies. - -To invert it, flip `default` to `"deny"` and allow just one subtree: - -## Allow only specific network hosts - -Every non-`fs` scope matches by `patterns` instead of `paths`. For `network`, a pattern is a host (or `host:port`), and the operations are `fetch`, `http`, `dns`, and `listen`. - -## Allow only specific bindings - -Bindings registered with the runtime are gated by the `binding` scope, matched by name via `patterns`. Bindings have no sub-operations, so pass `["*"]` for `operations`. - -The `childProcess`, `process`, and `env` scopes work the same way: `childProcess` patterns match the command (`operations: ["spawn"]`), `env` patterns match the variable name (`operations: ["read", "write"]`), and `process` is matched by pattern with `operations: ["*"]`. - -## Combine policies and see denials - -Each policy above sets one scope, so you can spread several into one `permissions` object and bind them together. - -When a scope or matching rule denies an operation, the kernel rejects it with `EACCES` before any host resource is touched. For example, with `network: "deny"`, an outbound `fetch()` inside the guest throws: - -``` -EACCES: permission denied, tcp://example.com:80: blocked by network.http policy -``` \ No newline at end of file diff --git a/website/public/docs/docs/persistence.md b/website/public/docs/docs/persistence.md deleted file mode 100644 index 5733125903..0000000000 --- a/website/public/docs/docs/persistence.md +++ /dev/null @@ -1,66 +0,0 @@ -# Persistence & Sleep - -How agentOS persists files and manages sleep/wake cycles. - -agentOS persists the `/home/agentos` filesystem, durable session catalog, and completed session history across actor sleep. A later client call wakes a fresh VM. Adapter processes, running commands, shells, live subscriptions, and in-progress ACP deltas do not survive VM shutdown. - -## What persists across sleep - -| Data | Storage | Persists? | -|------|---------|-----------| -| Files in `/home/agentos` | Actor SQLite over UDS | Yes | -| Preview URL tokens | Actor SQLite | Yes | -| Session catalog and configuration | Actor SQLite over UDS | Yes | -| Completed ACP session history | Actor SQLite over UDS | Yes | -| Live ACP adapter process | VM memory | No; restored lazily | -| In-progress message deltas | Live event stream | No | -| Cron job definitions | VM memory | No | -| Running processes | VM kernel | No | -| Active shells | VM kernel | No | -| In-memory mounts | VM memory | No | - -The native sidecar reads and writes filesystem chunks directly through the actor's authenticated SQLite Unix socket. File contents do not pass through the TypeScript or JavaScript actor layer. VM creation supplies one SQLite descriptor, which the sidecar resolves once and shares with filesystem metadata, filesystem blocks, and core session persistence; plugins do not open additional UDS or file connections. - -## Sleep and active turns - -An active prompt turn uses RivetKit's keep-awake scope through the terminal SQLite commit. An idle durable session does not keep the actor awake. - -```text -Actor becomes idle -> idle timeout -> actor sleeps and the VM shuts down - -listSessions/readHistory -> actor wakes -> VM boots -> SQLite is read without starting an adapter - -prompt -> actor wakes -> VM boots -> adapter is restored lazily -> turn runs -``` - -RivetKit's default idle sleep timeout is 30 seconds. agentOS sets the graceful shutdown budget to 15 minutes and the action timeout to the largest Node timer-safe delay (2,147,483,647 ms, about 24.8 days), so a normal human permission review is not cut off by the previous 15-minute bound. These can be changed through the actor's `options` configuration. - -## Sleep vs destroy - -| | Sleep | Destroy | -|-|-------|---------| -| Filesystem | Preserved | Deleted | -| Preview tokens | Preserved | Deleted | -| Session catalog and completed history | Preserved | Deleted | -| Adapter process, live deltas, and subscriptions | Lost; restored or recreated as needed | Lost | -| Processes and shells | Lost | Lost | - -## VM lifecycle events - -Use native RivetKit subscriptions, `connection.on("vmBooted", ...)` and `connection.on("vmShutdown", ...)`, to observe actor-owned VM lifecycle changes. These are hosting events and are intentionally absent from Core. - -## Reading durable state after sleep - -When the actor wakes, a fresh VM is created over the same actor SQLite database. Files under `/home/agentos`, the session catalog, and completed history remain available. `listSessions()`, `getSession()`, and `readHistory()` read that stored state without starting an ACP adapter. Prompting an existing session ID restores its adapter lazily, preferring native ACP `session/load` when supported and falling back to a new adapter session with bounded durable history context when necessary. - -Live subscriptions resume only from new events. Ephemeral message deltas that had not completed before shutdown are not reconstructed. - -## SQLite tables - -`agentos_fs_metadata_heads` and `agentos_fs_metadata_chunks` store the chunked inode and directory metadata for each filesystem namespace. `agentos_fs_blocks` stores content-addressed file chunks. - -`agentos_core_sessions` stores durable session metadata and cached ACP negotiation state. `agentos_core_events` stores exact native ACP payloads plus a compact scalar AgentOS envelope. `agentos_core_prompts`, `agentos_core_permission_records`, and `agentos_core_permission_outcomes` store bounded prompt, idempotency, and permission bookkeeping. The sidecar treats SQLite as the source of truth; it does not depend on adapter-owned history for listing or reading sessions. - -The filesystem, core, and TypeScript actor independently own `agentos_fs_schema_version`, `agentos_core_schema_version`, and `agentos_actor_schema_version`. There is no shared schema-version table or global migration sequence. `agentos_actor_preview_tokens`, `agentos_actor_dynamic_mounts`, and `agentos_actor_linked_software` are actor-owned hosting metadata. - -This per-VM database is trusted plaintext storage. Session environment values, MCP credentials, prompts, messages, and tool or permission payloads may be stored without encryption or redaction so they can survive sleep. Protect database and backup access accordingly. See [Sessions & Persistence](/docs/architecture/sessions-persistence/) for exact event storage and retention bounds. \ No newline at end of file diff --git a/website/public/docs/docs/processes.md b/website/public/docs/docs/processes.md deleted file mode 100644 index 80571af6c2..0000000000 --- a/website/public/docs/docs/processes.md +++ /dev/null @@ -1,23 +0,0 @@ -# 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. - -## Spawn a long-running process - -Use `spawn` for processes that run in the background. Call `connect()` and subscribe to native `processOutput` and `processExit` events, filtering their `pid` in application code. - -## Write to stdin - -Send input to a running process. - -## Process lifecycle - -## Interactive shells - -Open an interactive shell with PTY support. Subscribe to native `shellData`, `shellStderr`, and `shellExit` events, filtering their `shellId` in application code. \ No newline at end of file diff --git a/website/public/docs/docs/python.md b/website/public/docs/docs/python.md deleted file mode 100644 index ae67b7c6ed..0000000000 --- a/website/public/docs/docs/python.md +++ /dev/null @@ -1,80 +0,0 @@ -# Python - -Execute Python source, files, modules, and package workflows in agentOS. - -agentOS runs CPython 3.13 as a first-class VM execution engine. Python shares the -VM filesystem, process tree, networking, permissions, and limits with agents, -Bash, JavaScript, and installed software. - -Letting an agent write code instead of chaining one tool call per step is called -[Code Mode](https://blog.cloudflare.com/code-mode/). It has a few advantages over -driving [Bash](/docs/bash): - -- **Fewer tokens**: Ten chained operations cost one round trip, not ten. -- **Real data processing**: Comprehensions and `pandas` instead of `jq` and `awk`. -- **The package ecosystem**: `pip install` whatever the task needs. -- **Concurrency**: `asyncio` instead of shell job control. - -## Evaluate an expression - -`evaluate()` returns a JSON-serializable value. - -A value the JSON encoder can't represent fails with -`evaluation_serialization_failed` rather than silently losing the value. - -## Execute code - -`execute()` runs source and captures its output instead of returning a value. - -Executions are ephemeral, so capture stdio only when you want it — `"stderr"` for -diagnostics, `"all"` for both streams. `onStdout`/`onStderr` stream live and work -independently of capture. - -## Pass data into code - -`inputs` hands host values to the guest as real objects, so data never gets -interpolated into source. - -## Keep state between calls - -Pass a `contextId` to keep globals, functions, imports, and modules alive in one -interpreter. - -Only inline `execute()`/`evaluate()` retain memory. Files, modules, installs, and -Bash may pass the same id, but they run fresh. A context runs one operation at a -time — reusing a busy `contextId` fails immediately. - -## Files, modules, and async - -Awaited work counts against the deadline; unawaited `asyncio` tasks are not -promised to survive between operations. - -## Install packages - -Installs modify the VM-wide filesystem, so a package installed once is importable -by every later execution in that VM, in any language. Only one npm/Python -mutation runs at a time per VM; a concurrent install fails with `execution_busy`. - -## Background processes and web servers - -`spawn*` starts a long-lived process and returns a `pid`. From there you get -stdin, output, signals, and waiting. - -## A full Linux environment underneath - -There is a real Linux environment behind all of this, shared by every language. -Files and installed packages are immediately visible to Bash, JavaScript, agents, -and other executions. - -See [Filesystem](/docs/filesystem), [Processes & Shells](/docs/processes), and -[Networking & Previews](/docs/networking). - -## Bindings - -Python calls [bindings](/docs/bindings) as normal commands via `subprocess`, so -host credentials stay outside the VM. - -## Permissions, limits, and timeouts - -Every operation inherits the VM [permission policy](/docs/permissions) and -[resource limits](/docs/resource-limits). \ No newline at end of file diff --git a/website/public/docs/docs/quickstart.md b/website/public/docs/docs/quickstart.md deleted file mode 100644 index fdd5ae6416..0000000000 --- a/website/public/docs/docs/quickstart.md +++ /dev/null @@ -1,69 +0,0 @@ -# Quickstart - -Set up an agentOS actor, create a session, and run your first coding agent. - -Use this pre-built prompt to get started faster. - - -Prefer to read code? Clone the example repository. -View on GitHub - - OS - Client - JS · Browser · Backend - Server - OS - = agentOS VM - -1. **Install** - - - **@rivet-dev/agentos** — Actor framework with built-in persistence and orchestration - - **@agentos-software/pi** — [Pi](https://github.com/mariozechner/pi-coding-agent) coding agent. [Claude Code](/docs/agents/claude), [Codex](/docs/agents/codex), and [OpenCode](/docs/agents/opencode) install the same way. - - ```bash - npm install @rivet-dev/agentos @agentos-software/pi - ``` - -2. **Create the server** - -3. **Create the client** - - The client can be any public frontend or another backend. The same `vm` actor is reachable from a plain Node script, a browser/React app, or a separate server. - -4. **Run it** - - Start the server, then run the client in a second terminal: - - ```bash - # Terminal 1: start the server - npx tsx server.ts - - # Terminal 2: run the client - npx tsx client.ts - ``` - - With the server running, open http://localhost:6420/ui to watch the VM in the [inspector](/docs/inspector): the live transcript, the filesystem, and its processes. - -5. **Customize** - - Now that you have a working agent, customize it to fit your needs: - - - **[Software](/docs/software)** — Install software packages inside the VM - - **[Filesystem](/docs/filesystem)** — Read, write, and manage files inside the VM - - **[Permissions & Resource Limits](/docs/permissions)** — Gate what the agent can do and cap its resource usage - - **[Bindings](/docs/bindings)** — Expose your JavaScript functions to agents as CLI commands - -5. **Deploy** - - By default, agentOS runs locally with `npx rivetkit dev` — no infrastructure needed. To run in production, deploy to any of these targets: - - See [Deployment](/docs/deployment) for managed, self-hosted, and direct VM options. - -agentOS is in preview and the API is subject to change. If you run into issues, please [report them on GitHub](https://github.com/rivet-dev/rivet/issues) or [join our Discord](https://rivet.dev/discord). - -## Direct VM API - -The same `@rivet-dev/agentos` package also exports `AgentOs.create()` for direct -VM control without the actor lifecycle, multiplayer, or orchestration layer. - -See the [direct VM API documentation](/docs/core) for reference. \ No newline at end of file diff --git a/website/public/docs/docs/resource-limits.md b/website/public/docs/docs/resource-limits.md deleted file mode 100644 index 2ebe589d00..0000000000 --- a/website/public/docs/docs/resource-limits.md +++ /dev/null @@ -1,105 +0,0 @@ -# Resource Limits - -Cap per-VM resources, JavaScript CPU/wall-clock time, Python execution, and WASM runtime work so guest code can never exhaust the host. - -Every agentOS VM runs with **per-VM resource and runtime caps**. These caps contain runaway or malicious guest work to its VM and give the host an explicit failure instead of silent data loss. - -- **Secure defaults**: unset fields fall back to built-in defaults that match the runtime's historical constants. Optional execution budgets such as WASM fuel explicitly document when their default has no additional budget. -- **Per-VM**: every VM gets its own budget. Limits are not shared across VMs. -- **Enforced by the sidecar/runtime**: a guest that exceeds a cap fails inside the VM (out-of-memory, `EMFILE`, `EAGAIN`, runtime timeout, etc.) instead of consuming past the configured budget. -- **Operator-raisable**: the operator (the trusted process that creates the VM) may raise any cap for trusted workloads. Guest code can never raise its own caps. - -## Setting limits - -Set caps on the `limits` object in the `agentOS` config. Limits are grouped by subsystem (`resources`, `process`, `jsRuntime`, `python`, `wasm`, and more). Omitted limits keep their secure default. - -## Available caps - -| Limit | Controls | Notes | -|---|---|---| -| `resources.maxProcesses` | Concurrent processes in the VM process table | Caps fork bombs and runaway spawning. New spawns fail with `EAGAIN`. | -| `resources.maxOpenFds` | Open file descriptors | Exhausting the table fails with `EMFILE` / `ENFILE`. | -| `resources.maxSockets` | Open sockets in the socket table | Bounds concurrent connections; excess `connect`/`accept` fail. | -| `resources.maxFilesystemBytes` | Total bytes stored in the virtual filesystem | Bounds VFS storage; writes past the budget fail with a no-space error. | -| `resources.maxInodeCount` | Inodes retained by the virtual filesystem | Default is `16384`; creating another file or directory fails with a no-space error. This is the expected upper bound for filesystem-schema sizing and benchmarks. | -| `resources.maxWasmFuel` | WASM execution budget | Bounds WASM execution work; unset means no explicit fuel budget. | -| `resources.maxWasmMemoryBytes` | WASM linear memory, in bytes | Default is `128 MiB`. | -| `resources.maxWasmStackBytes` | Maximum WASM call-stack size, in bytes | Deep recursion fails with a stack overflow instead of crashing the VM. | -| `resources.maxBlockingReadMs` | AgentOS safety backstop for otherwise-blocking guest operations | Default is `30000`. Socket waits, poll, and contended `F_SETLKW` warn near the limit and fail with `ETIMEDOUT` if it expires; raise it for workloads that intentionally wait longer. Linux has no equivalent global backstop. | -| `process.pendingStdinBytes` | Stdin accepted by the sidecar but not yet written into kernel pipes | Default is `64 MiB` per process and across the VM. Sibling processes share the same aggregate envelope, so this is a tighter bound for multi-process workloads. A non-draining process rejects further writes with an error naming `limits.process.pendingStdinBytes`. | -| `process.pendingEventCount` | Event count at each bounded VM/process delivery-queue stage | Default is `10000`. The crossing event is rejected with an error naming `limits.process.pendingEventCount`; it is never silently dropped. | -| `process.pendingEventBytes` | Retained process-event bytes at each bounded delivery-queue stage | Default is `64 MiB` per process and across all process queues in the VM. Sibling processes share the VM-wide envelope. Large stdout/stderr bursts are rejected with an error naming `limits.process.pendingEventBytes`, independently of event count. | -| `acp.maxSessionsPerVm` | Durable sessions retained in one VM SQLite database | Default is `10000`. Opening another session fails with a typed error naming this field. | -| `acp.maxPromptsPerSession` | Prompt and idempotency records retained for one durable session | Default is `100000`; it must not exceed `acp.maxPromptsPerVm`. | -| `acp.maxPromptsPerVm` | Prompt and idempotency records retained across one VM | Default is `1000000`. | -| `acp.maxPendingPermissionsPerSession` | Actionable ACP permission requests for one session | Default is `1000`; it must not exceed `acp.maxPendingPermissionsPerVm`. | -| `acp.maxPendingPermissionsPerVm` | Actionable ACP permission requests across one VM | Default is `10000`. | -| `acp.maxPermissionOutcomesPerSession` | Terminal ACP permission outcomes retained for one session | Default is `10000`; it must not exceed `acp.maxPermissionOutcomesPerVm`. | -| `acp.maxPermissionOutcomesPerVm` | Terminal ACP permission outcomes retained across one VM | Default is `100000`. Old outcomes are bounded independently from pending requests. | -| `jsRuntime.v8HeapLimitMb` | Guest JavaScript V8 heap, in MiB | Default is `128`. | -| `jsRuntime.cpuTimeLimitMs` | Active JavaScript CPU time | Default is `30000`; `0` disables the CPU watchdog. | -| `jsRuntime.wallClockLimitMs` | JavaScript elapsed wall-clock backstop | Default is `0`, disabled. Use this for finite commands, not long-lived adapters. | -| `jsRuntime.importCacheMaterializeTimeoutMs` | Node import-cache materialization timeout | Default is `30000`. | -| `jsRuntime.syncRpcWaitTimeoutMs` | JavaScript sync host-RPC wait | Unset keeps the engine default, currently `30000`. | -| `python.executionTimeoutMs` | Python execution wall-clock timeout | Default is `300000`. | -| `python.maxOldSpaceMb` | Pyodide runner V8 old-space heap, in MiB | Default is `0`, which keeps the engine default. | -| `wasm.prewarmTimeoutMs` | WASM compile-cache warmup timeout | Default is `30000`. | -| `wasm.runnerHeapLimitMb` | Trusted WASI/WASM runner V8 heap, in MiB | Default is `2048`; this is not guest linear memory. | -| `wasm.runnerCpuTimeLimitMs` | Trusted WASI/WASM runner active-CPU budget | Default is `30000`; `0` disables this budget for trusted configurations. | -| `process.maxSpawnFileActions` | File actions decoded for one `posix_spawn` call | Default is `4096`; excess actions fail with `E2BIG`. | -| `process.maxSpawnFileActionBytes` | Serialized file-action bytes for one `posix_spawn` call | Default is `1 MiB`; excess input fails with `E2BIG`. | - -## Behavior at the limit - -- **WASM stack**: deep recursion throws a stack-overflow error in the guest, never a host crash. -- **JavaScript CPU time**: CPU-bound loops terminate with a CPU-budget error once active JS CPU exceeds `jsRuntime.cpuTimeLimitMs`. -- **JavaScript wall time**: awaiting or blocked JS terminates only when you set `jsRuntime.wallClockLimitMs`; the default is disabled for long-lived adapters. -- **Filesystem bytes**: writing past the VFS budget fails with a no-space error to the guest. -- **Counts (fds / processes / sockets)**: hitting a table cap returns the standard POSIX errno appropriate to that cap (`EMFILE`/`ENFILE`, `EAGAIN`, etc.). -- **Durable ACP collections**: session, prompt, pending-permission, and terminal-outcome caps fail atomically with typed errors naming the exact `limits.acp.*` field to raise. Per-session caps are validated not to exceed their corresponding per-VM cap. - -### WASM memory residency calls - -V8 owns the physical backing pages for WASM linear memory, and the runtime -cannot currently pin those pages against host swapping. Nonempty `mlock()` and -valid `mlockall()` requests therefore return `ENOTSUP` rather than falsely -claiming that secrets or other guest memory were pinned. `munlock()` and -`munlockall()` succeed because no guest lock can be established and the memory -is already unlocked. - -Non-destructive `madvise()` access-pattern calls are accepted as best-effort -hints, which Linux is also permitted to ignore. Advice that would discard data -or change fork, core-dump, or host VM mapping policy returns `ENOTSUP` because -the runtime cannot apply it. - -## Sidecar liveness - -Separate from the guest caps above, the host detects a dead or wedged sidecar -process by silence, not by per-request deadlines. The sidecar emits a liveness -heartbeat every 10 seconds from a dedicated thread — so it keeps beating even -mid-way through a long turn — and the host treats 30 seconds with no inbound -frames at all as a dead sidecar: it kills the process and fails in-flight -requests with a typed `SidecarSilenceTimeout` error. - -Because liveness is silence-based, individual requests have no time limit of -their own: an agent turn may legitimately run for many minutes without being -torn down. Neither the heartbeat cadence nor the silence window is -configurable — they are fixed protocol constants. - -## Warnings & observability - -Limits are observable, not just enforced. Live resource gauges and internal -bounded queues are tracked in a central limit registry that: - -- **Warns before the limit is hit.** As usage crosses ~80% of a cap, the runtime - emits a structured warning (once per crossing, re-armed only after it recovers), - so a slow consumer or a runaway guest is visible *before* it fails. -- **Never drops data silently.** Internal queues either apply backpressure or - fail with a typed error naming the exhausted limit and the setting used to - raise it. A rejected event is not popped and forgotten. -- **Surfaces through logs.** The agentOS sidecar logs to stderr (stdout is the wire - protocol); set `AGENTOS_LOG=warn` (the default) to see near-limit warnings - or `AGENTOS_LOG=debug` for live per-limit usage snapshots. - -See [Limits & Observability](/docs/architecture/limits-and-observability) for the -full architecture. \ No newline at end of file diff --git a/website/public/docs/docs/sandboxes.md b/website/public/docs/docs/sandboxes.md deleted file mode 100644 index dd442b3352..0000000000 --- a/website/public/docs/docs/sandboxes.md +++ /dev/null @@ -1,128 +0,0 @@ -# External Sandboxes - -Extend agentOS with full sandboxes for heavy workloads like browsers, desktop automation, and compilation. - -Pair agentOS with a full sandbox on demand for heavy workloads. The sandbox -filesystem mounts into the VM as a native directory, and its process management -is exposed as [bindings](/docs/bindings) — provider-agnostic through -[Sandbox Agent](https://sandboxagent.dev). - -- agentOS covers most use cases; a sandbox adds a full Linux environment for - special software. -- Lazily start a sandbox only when a task needs it, then tear it down. -- One agent session can mix lightweight coding with heavy system work. -- See [agentOS vs Sandbox](/docs/versus-sandbox) for the full comparison. - -## When to use a sandbox - -- **Native binaries** not yet supported in the agentOS runtime. -- **Browsers / desktop automation** — Playwright, Puppeteer, Selenium, anything - needing a display server. -- **Heavy compilation** — large builds or native toolchains. -- **GUI apps** — desktop apps, VNC, graphical workloads. -- **npm packages with native extensions** — `sharp`, `bcrypt`, - `better-sqlite3`. - -Default to the agentOS VM; spin up a sandbox only when required. Sandboxes bill -per second of uptime. - -## Getting started - -Ships as `@rivet-dev/agentos-sandbox`, working through two mechanisms: - -- **Filesystem mount** — projects the sandbox into the VM as a native - directory. Read/write files through the mount. -- **Bindings** — exposes sandbox process management as - [bindings](/docs/bindings). Run commands on the sandbox from the VM. - -Both powered by [Sandbox Agent](https://sandboxagent.dev); swap providers -without changing agent code. - -```bash -npm install @rivet-dev/agentos-sandbox sandbox-agent -``` - -- `createSandboxFs`, `createSandboxBindings` — from `@rivet-dev/agentos-sandbox`. -- `SandboxAgent` + provider helpers (e.g. `docker`) — from `sandbox-agent`. -- Pass a provider as `sandbox: { provider: docker() }`. agentOS starts the - client, mounts it at `/mnt/sandbox`, registers process bindings, and disposes - it with the VM. -- In RivetKit actors, pass the provider to `agentOS(...)` — a fresh client per - actor VM. - -## Configuration - -The sandbox is mounted at `/mnt/sandbox` by default. The `sandbox` object also -accepts these options alongside `provider` or `client`: - -| Option | Purpose | -| --- | --- | -| `mountPath` | Changes the directory where the external filesystem appears inside the agentOS VM. | -| `sandboxRoot` | Restricts the mount to a directory inside the external sandbox instead of exposing its root. | -| `readOnly` | Prevents the VM from modifying files through the mount. Defaults to `false`. | -| `timeoutMs` | Sets the per-request timeout for Sandbox Agent filesystem calls. | -| `maxFullReadBytes` | Bounds files buffered by full-read and truncate fallbacks. | - -The server example above changes `mountPath` to -`/home/agentos/sandbox`. Paths used inside the external sandbox remain relative -to `sandboxRoot`, so a VM file such as `/home/agentos/sandbox/app/index.ts` maps -to `/app/index.ts` when `sandboxRoot` is `/`. - -## Calling the mounted bindings - -Write code through the filesystem, run it inside the sandbox. Bindings are a CLI -command, called through the same `exec`/`spawn` surface as any command. - -## Bindings reference - -```bash -# Run a command synchronously -agentos-sandbox run-command --command "npm install" --cwd "/app" - -# Start a background process -agentos-sandbox create-process --command "npm" --args "run" --args "dev" - -# List running processes -agentos-sandbox list-processes - -# Get process output -agentos-sandbox get-process-logs --id "proc_abc123" - -# Stop or kill a process -agentos-sandbox stop-process --id "proc_abc123" -agentos-sandbox kill-process --id "proc_abc123" - -# Send input to an interactive process -agentos-sandbox send-input --id "proc_abc123" --data "yes" -``` - -## Sandbox providers - -The package provides isolated entrypoints for Docker, local execution, E2B, -Daytona, Vercel, Cloudflare, Modal, ComputeSDK, and Sprites. Import only the -provider you use (for example, `@rivet-dev/agentos-sandbox/e2b`) so its optional -SDK is isolated from the rest of your application. Docker is also exported from -the package root, as shown above. - -Install the provider's SDK when required: `@e2b/code-interpreter` for E2B, -`@daytonaio/sdk` for Daytona, `@vercel/sandbox` for Vercel, -`@cloudflare/sandbox` for Cloudflare, `modal` for Modal, `computesdk` for -ComputeSDK, or `@fly/sprites` for Sprites. Docker and local execution need no -additional provider SDK. - -For another backend, adapt any [Sandbox Agent](https://sandboxagent.dev) -provider with `sandboxAgentProvider` from `@rivet-dev/agentos-sandbox`. Provider -mode is the preferred lifecycle: each VM gets a fresh sandbox, and disposal of -the VM destroys it. - -## Advanced: mount an existing client - -Standalone `AgentOs.create()` can mount an already-connected, -Sandbox-Agent-compatible client. Install `sandbox-agent` directly for this -manual path. The caller owns the client by default; set `dispose` to `true` when -the client implements disposal, or provide a callback to transfer lifecycle -ownership to the VM. - -RivetKit `agentOS()` intentionally rejects the `client` form because one client -cannot be shared safely across actor VMs. Pass a `provider` there so every actor -VM starts and owns a fresh sandbox. \ No newline at end of file diff --git a/website/public/docs/docs/security-model.md b/website/public/docs/docs/security-model.md deleted file mode 100644 index 20a2951134..0000000000 --- a/website/public/docs/docs/security-model.md +++ /dev/null @@ -1,172 +0,0 @@ -# Security Model - -Trust boundaries, isolation guarantees, and the agentOS threat model. - -agentOS is in beta and still undergoing security review. The security model described here is subject to change. - -agentOS is a sandbox: it runs **untrusted code safely on behalf of a trusted caller**. Every actor boots its own fully virtualized VM with a virtual filesystem, process table, socket table, pipes, PTYs, a permission policy, and managed language runtimes. Guest JavaScript executes in a V8 isolate, and every guest syscall is serviced by the kernel rather than the host. There are no host escapes: guest code cannot spawn a real host process, touch the real host filesystem, or open a real host network socket. - -## Deny by default - -No syscalls are bound to the system by default. Everything is denied until explicitly opted in. - -- **Network access** is denied until you opt in with a `network` permission. -- **Filesystem mounts** expose nothing of the host until you configure them. -- **Process spawning** runs only kernel-managed guest processes, never host processes. -- **All other host capabilities** must be configured by the host before the VM can use them. - -Other in-VM scopes (the virtual filesystem, child processes, process info, env) are enabled so that normal programs run, but they are mediated entirely by the kernel and never touch the host. - -## Trust model: three components - -Before judging whether something is a security bug, decide which side of the boundary it is on. agentOS has three components with very different trust levels. - - Client - (trusted) - Your host app - Configures the VM - Untrusted: only the - code it submits - Sidecar / Kernel - (trusted = TCB) - Owns VFS, processes, - sockets, policy - Enforces the - boundary - Executor - (untrusted = adversary) - V8 isolate / WASM - Runs guest code - Assume actively - hostile - wire - syscalls - SECURITY BOUNDARY - - - -### Client (trusted) - -The party that configures and manages the VM: your application code, container, or serverless function. - -- The client process and **every value it sends** are trusted: VM config, mount descriptors and their plugin configs (host directory paths, S3 endpoints and credentials, etc.), the permission policy, network allowlist, resource limits, env, and DNS overrides. -- **Configuration is not an attack surface.** A defect that requires the client to supply a malicious config, endpoint, credential, or policy is not a sandbox vulnerability: the client is configuring its own VM and already controls the host. -- The **one** thing from the client that is *not* trusted is the **code/payload** it asks to run, because that runs in the executor. How code reached the executor never makes it trusted. - -You are responsible for hardening this side. See [What you are responsible for](#what-you-are-responsible-for). - -### Sidecar / kernel (trusted, the enforcement point) - -The trusted computing base. It brokers client requests and owns the kernel, VFS, mount/plugin registry, socket table, and permission policy. It is responsible for enforcing the boundary against the executor. - -### Executor (untrusted, the adversary) - -V8 isolates or WASM running guest JS/Python/WASM plus any third-party, npm, or agent-generated code. - -- Assume everything here is **actively hostile**. -- The executor reaches the outside world only through kernel-owned VFS, process, socket, pipe, PTY, permission, and DNS paths. - -## The security boundary - -**The security boundary is sidecar ↔ executor.** The runtime must stop guest code in the executor from: - -- Escaping the kernel boundary (the real host filesystem, network, process table, or memory). -- Bypassing the **applied** permission policy, allowlist, or limits. -- Exhausting host resources beyond configured bounds. -- Reading another VM's state. - -Two corollaries that are easy to get wrong: - -- **Trusted policy, untrusted subject.** The permission policy and limits are trusted input, but the guest executor is the subject they bind. "Guest bypasses an applied permission, egress rule, or resource cap" is in-scope and serious. Trusted = who sets the rule; untrusted = who is bound by it. -- **Trusted mount, untrusted traffic.** A host-backed mount (host directory, S3, etc.) comes from trusted config, so its existence, target, and credentials are not attack surface. But the guest drives I/O through it, so confining those guest operations to the mount root (symlink, `..`, TOCTOU, and path-aliasing escapes) is in-scope. - -### In scope vs out of scope - -| In scope (sandbox escape) | Out of scope (not a sandbox bug) | -| --- | --- | -| Guest reaches the real host fs / net / process / memory | Client supplies a malicious config / endpoint / credential / policy | -| Guest bypasses an applied permission, egress rule, or limit | Hardening that only guards trusted client-provided configuration | -| Guest exhausts host resources past configured bounds | Wire-level authn/authz between mutually distrusting clients | -| Guest reads another VM's state | VM-to-VM access via forged connection IDs (single-client transport) | -| Guest escapes a host-backed mount root (symlink / `..` / TOCTOU) | The existence or target of a configured mount | - -**Transport scope.** The wire protocol is same-version lockstep and single-client over stdio (one trusted client per sidecar process). There is no second, mutually-distrusting client, so wire-level authn/authz between clients and VM-to-VM access via forged connection IDs are out of scope until a multi-client transport exists. - -## VM isolation - -Each agentOS actor runs in its own isolated VM. - -- **Sandboxed execution.** All agent code runs inside a V8 isolate with WebAssembly. No code escapes the isolate boundary. -- **Virtual filesystem.** The VM has its own in-memory filesystem. Guest reads and writes never reach the real host filesystem. Agents cannot access host files unless explicitly mounted. -- **Virtual network.** The VM has no direct access to the host network. Outbound requests are proxied through the host with configurable controls. -- **Process isolation.** No host process is visible or accessible from inside the VM. -- **Per-actor containment.** Each actor is its own VM. Two actors share no filesystem, globals, module state, memory, or crash fate. The sidecar process that hosts those VMs may be shared by default as a performance optimization, but isolation is enforced at the VM level, not the host-process level. - -### Kernel-owned syscall paths - -Every guest syscall is mediated by the kernel and checked against the runtime's permission policy. Concretely, the kernel mediates: - -- **Filesystem.** A virtual, in-memory filesystem. Guest reads and writes never reach the real host filesystem. Host data enters the VM only through the `files`, `mounts`, or `nodeModules` you configure explicitly. See [Filesystem](/docs/filesystem). -- **Processes.** `node:child_process` spawns kernel-managed guest processes, never real host processes. Children can only run the commands the VM mounts (WASM-backed `sh` and coreutils, V8-backed `node`). See [Processes](/docs/processes). -- **Network.** Guest `fetch()`, `node:http`, and raw sockets all flow through the kernel socket table. Guest `fetch()` runs through undici inside the isolate and then through the kernel socket table; it never opens a real host socket. See [Networking](/docs/networking). -- **DNS, pipes, and PTYs** are likewise kernel-owned: no guest path reaches the host directly. -- **Bindings.** Registered [bindings](/docs/bindings) are the only sanctioned way to hand the guest a named host capability. The guest invokes a binding by name with JSON input, the call round-trips to the host handler, and only the handler's return value comes back. The guest never receives the underlying host access. - -## What enters the VM - -The host filesystem is never exposed to the guest by default. Host data crosses the boundary only through options you configure: - -- **`files`** seed bytes into the virtual filesystem. The bytes are copied in; the host path is never exposed. -- **`mounts`** project a host directory at a guest path, Docker-style. The guest sees only the mounted subtree, read through the VFS lazily, never the wider host filesystem. Mounts are read-only unless you opt out. -- **`nodeModules`** project a host `node_modules` directory (read-only, lazily) at a guest path so guest `import`/`require` resolves real installed packages. - -In every case the guest sees only the subtree you mount, and writes to read-only mounts are rejected. - -## Permissions - -Permissions are the capability gate at the boundary. They merge over a secure default that denies the network and enables the filesystem, child processes, process info, and env. Because the merge is partial, you name only the scope you change. - -```ts -// Grant network egress; everything else keeps the secure defaults. -permissions: { network: "allow" } -``` - -A scope can be `"allow"`, `"deny"`, or a `{ default, rules }` policy that matches request patterns. Guest servers are reachable only over loopback inside the VM unless you exempt a port explicitly. See [Permissions](/docs/permissions) and [Networking](/docs/networking) for the full policy shape. - -## Resource and timing limits - -The VM bounds guest execution so runaway or hostile code cannot hang or exhaust the host: - -- **Timeouts and cancellation** kill or cancel a run from the outside. -- **Memory, CPU-time, and payload limits** are enforced by the VM. -- **Timing-side-channel mitigation.** In the default mode, high-resolution clocks (`Date.now()`, `performance.now()`, `process.hrtime()`) are frozen within a run and `SharedArrayBuffer` is removed, to blunt timing side channels of the kind used in Spectre-style attacks. - -See [Security & Auth](/docs/security-model) for resource limits, network control, and authentication setup. - -## What agentOS guarantees - -- Agent code cannot read or write host files outside configured mounts. -- Agent code cannot make network requests except through the host proxy. -- Agent code cannot access host environment variables or secrets. -- Each actor's filesystem, sessions, and state are isolated from other actors. -- Resource limits (CPU, memory) are enforced at the VM level. -- A crash, resource exhaustion, or escape attempt is contained to a single VM; other VMs keep running, even when they share a sidecar process. - -## What you are responsible for - -The boundary protects the host from the guest. It does **not** harden your host process against everything else. The VM alone is not enough without a hardened host, and a hardened host alone does not protect against code that runs with full host access inside your own process. - -- Hardening the host process and deployment environment. For internet-facing workloads that take untrusted input, run your host inside an already-hardened environment (for example AWS Lambda, Google Cloud Run, or a similar sandboxed platform). -- Validating authentication tokens in `onBeforeConnect`. -- Scoping [permissions](/docs/permissions) appropriately for your use case. -- Managing API keys and secrets on the host side (see [Models & Credentials](/docs/models-and-credentials)). -- Configuring [resource limits and network controls](/docs/security-model) to match your threat model. -- Choosing your blast radius: prefer a fresh VM per untrusted or high-risk task so an escape attempt cannot outlive a single VM. - -The boundary contains guest code, but you still own the host. Treat the host process as trusted infrastructure and harden it. - -## Further reading - -- [Security configuration](/docs/security-model) for resource limits, network control, and authentication setup -- [Permissions](/docs/permissions) for agent tool-use approval patterns -- [agentOS vs Sandbox](/docs/versus-sandbox) for when to escalate to a full sandbox \ No newline at end of file diff --git a/website/public/docs/docs/sessions.md b/website/public/docs/docs/sessions.md deleted file mode 100644 index 44f4f84c86..0000000000 --- a/website/public/docs/docs/sessions.md +++ /dev/null @@ -1,131 +0,0 @@ -# Sessions - -Open durable ACP sessions, prompt them, read history, and restore adapters. - -AgentOS sessions are durable records backed by the VM's SQLite database. - -- The public session ID is stable across VM sleep and adapter restarts. -- The adapter's private ACP session ID stays internal. -- The [inspector](/docs/inspector)'s Transcript tab renders the same session stream live, with a composer for prompting sessions by hand. - -## Open a session - -`openSession` creates or restores a session, completes ACP negotiation, and -resolves without a value. - -- Choose and retain the `sessionId` before calling; omitted → `main`. -- `getSession` — call separately for durable metadata. -- Idempotent to repeat; changing immutable creation options for an existing ID - returns `session_conflict`. - -Input fields: `agent`, `cwd`, `additionalDirectories`, `env`, `mcpServers`, -`permissionPolicy`, `skipOsInstructions`, `additionalInstructions`. - -- Omitted `cwd` → `/home/agentos`. -- Actor deployments inject their SQLite database automatically; standalone core - clients must configure a VM SQLite file or descriptor. - -## MCP servers - -- MCP config belongs to the session — its tools are part of the agent's runtime - context. -- Configure local child-process or remote servers **before** opening the - session. -- Config path and transports come from the selected agent adapter (e.g. Pi - reads `.mcp.json` from its AgentOS home). -- Install local MCP server packages before opening the session so first-run - package-manager output can't corrupt a stdio handshake. -- See the [agent guide](/docs/agents/pi) for adapter specifics. - -## Prompt - -- `prompt` accepts native ACP `ContentBlock[]` — not a special text format. -- Never creates a missing session. -- The complete user message is committed before dispatch; a prompt whose - delivery may have reached the adapter is never auto-replayed. -- Bounded by `limits.acp.maxPromptBytes` and `limits.acp.maxPromptBlocks`; limit - errors name the field to raise. -- An oversized durable update batch is rejected before it changes history. - -- `idempotencyKey` — use when the caller may retry. Reusing a key with different - content fails; retrying while the first call is active waits and returns its - committed result. - -## Events and history - -`sessionEvent` is a flat discriminated union. - -- Top-level `type` = native ACP `SessionUpdate.sessionUpdate` value; ACP payload - fields (`content`, `toolCallId`, `entries`) sit beside the durability - envelope. No nested `update` wrapper. -- `durability: "ephemeral"` — live agent-message/thought delta; not sequenced or - stored. -- `durability: "durable"` — has a session sequence, emitted only after its - SQLite commit. Completed/coalesced message chunks are durable. -- Permission request/response variants use the same flat shape with top-level - `options`, `toolCall`, or `outcome`. - -- `readHistory({ sessionId, before, after, limit })` — SQLite-only, never starts - an adapter. `before`/`after` are exclusive and mutually exclusive. Dedup live - durable delivery by `(sessionId, sequence)`. -- Also SQLite-only reads: `getSession`, `listSessions`, `getSessionConfig`, - `getSessionCapabilities`, `getSessionAgentInfo`. Listing uses an opaque keyset - cursor — not a frozen snapshot. - -## Restoration - -After VM sleep, the next `prompt` transparently starts the adapter. AgentOS -tries, in order: - -1. Native ACP `session/resume`. -2. Stable `session/load`. -3. A fresh private ACP session with bounded continuation context from AgentOS - history. - -- Adapter replay during load is suppressed — SQLite is the sole history source - of truth. -- Fallback transcript bounded by `limits.acp.maxFallbackContinuationBytes`. -- AgentOS stores its own exact ACP updates because ACP has no portable - history-reading API and adapters restore inconsistently. - -## Permissions - -`permissionPolicy` is `reject_all`, `ask`, or `allow_all` (default -`allow_all`). - -- Controls how AgentOS answers native ACP permission requests — not VM - permissions or adapter tool access. -- Set `ask` when opening the session; subscribing alone doesn't change the - immutable policy. -- `ask` — durably records the request as a `permission_request` event. -- `allow_all` — resolves automatically, emits no permission event. -- Reply with the exact adapter-supplied `optionId` and explicit session ID: - -```ts -await agent.sessions.respondPermission({ - sessionId: request.sessionId, - requestId: request.requestId, - optionId: request.options[0].optionId, -}); -``` - -- First valid response wins atomically. -- Requests don't expire; cancellation, adapter exit, deletion, or VM shutdown - records a terminal reason. -- Accepted responses are sequenced in durable history. - -## Cancel, unload, and delete - -- `cancelPrompt` — cooperative ACP cancellation; returns `cancelled` or - `no_active_prompt`. -- `unloadSession` — releases the live adapter, keeps SQLite metadata/history; a - later prompt restores it. -- `deleteSession` — permanently removes the session and history. Omitted ID → - `main`; repeated deletion is idempotent. - -## Runtime configuration - -- `getSessionConfig` — returns the negotiated native ACP config collection + a - revision. -- `setSessionConfigOption` — may restore the adapter, lets ACP validate the - value, then replaces the cached collection. diff --git a/website/public/docs/docs/snippettest.md b/website/public/docs/docs/snippettest.md deleted file mode 100644 index 1d1fef339c..0000000000 --- a/website/public/docs/docs/snippettest.md +++ /dev/null @@ -1,5 +0,0 @@ -# Snippet Test - -temp - -# Snippet Test \ No newline at end of file diff --git a/website/public/docs/docs/software.md b/website/public/docs/docs/software.md deleted file mode 100644 index 19edcafb48..0000000000 --- a/website/public/docs/docs/software.md +++ /dev/null @@ -1,25 +0,0 @@ -# Software - -Install software packages and configure the commands available inside agentOS. - -agentOS ships with a common set of POSIX utilities (coreutils, sed, grep, gawk, findutils, diffutils, tar, gzip) out of the box. The `software` option installs additional packages, each providing one or more CLI commands. - -## Install - -```bash -npm install @rivet-dev/agentos @agentos-software/pi -``` - -Add packages like `@agentos-software/ripgrep` or `@agentos-software/jq` for anything beyond the default utilities. Browse the full catalog on the [Registry](/registry). - -## Usage - -Import the software packages you want, list them in the `software` array on the actor, then run commands through the client handle. - -## Available Packages - -Browse all available software packages on the [Registry](/registry). - -## Custom Software - -Package your own agents, command packages, and WASM commands. See [Software Definition](/docs/custom-software/definition) to define a package, and [Building Binaries](/docs/custom-software/building-wasm) to compile WASM commands from source in the [agentos registry](https://github.com/rivet-dev/agentos/tree/main/registry). \ No newline at end of file diff --git a/website/public/docs/docs/system-prompt.md b/website/public/docs/docs/system-prompt.md deleted file mode 100644 index a560f953d0..0000000000 --- a/website/public/docs/docs/system-prompt.md +++ /dev/null @@ -1,14 +0,0 @@ -# System Prompt - -How agentOS injects context into agent sessions. - -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. - -agentOS automatically injects a system prompt into every agent session that describes the VM environment and available commands and bindings. The prompt is additive and never replaces the agent's own instructions (CLAUDE.md, AGENTS.md, etc.). - -The base prompt is embedded in the sidecar (not written to a file inside the VM). At session start the sidecar assembles the base prompt with your additional instructions and generated binding docs, then injects the result into the agent adapter's launch arguments (for example, `--append-system-prompt` for Pi). - -## Customization - -- `additionalInstructions` appends session-specific text after the base OS prompt and before the generated binding docs, rather than replacing the agent's own instructions. -- `skipOsInstructions` suppresses the base OS prompt while still injecting the generated binding docs. \ No newline at end of file diff --git a/website/public/docs/docs/versus-sandbox.md b/website/public/docs/docs/versus-sandbox.md deleted file mode 100644 index 1d9ef9eb69..0000000000 --- a/website/public/docs/docs/versus-sandbox.md +++ /dev/null @@ -1,49 +0,0 @@ -# agentOS vs Sandbox - -When to use the lightweight agentOS VM, a full sandbox, or both together. - -- **agentOS** is a lightweight VM that runs inside your process. Near-zero cold start, low memory, direct backend integration via [bindings](/docs/bindings). -- **Sandboxes** are full Linux environments with root access, system packages, and native binary support. -- **You can use both.** agentOS works with sandboxes through the [external sandbox extension](/docs/sandboxes). Agents run in the lightweight VM by default and spin up a full sandbox on demand. - -## Comparison - -| | agentOS VM | Full Sandbox | -|---|---|---| -| **Cost** | Very low. Runs in your process. | Pay per second of uptime. | -| **Startup** | Near-zero cold start (~6 ms). | Seconds to spin up. | -| **Backend integration** | Direct. [Bindings](/docs/bindings) call your functions with zero latency. | Indirect. Requires network calls back to your backend. | -| **Credentials** | Stay on the host. [Bindings](/docs/bindings) run your functions server-side; agents see only inputs and outputs. | Must be injected into the sandbox environment. | -| **Permissions** | Granular, deny-by-default. | Coarse-grained (container-level). | -| **Infrastructure** | `npm install` | Vendor account + API keys. | -| **Best for** | Coding, file manipulation, scripting, API calls, orchestration. | Browsers, desktop automation, native compilation, dev servers. | - -## When to use each - -### agentOS VM - -Use the lightweight VM for most agent workloads: - -- Coding and file editing -- Running scripts and CLI tools -- Calling APIs and services via bindings -- Multi-agent orchestration and workflows -- Tasks where backend integration matters (permissions, tool access, LLM routing) - -### Full sandbox - -Spin up a sandbox when the workload needs a real Linux kernel: - -- Browsers and desktop automation (Playwright, Puppeteer, Selenium) -- Heavy compilation and native toolchains -- Dev servers with hot reload, databases, and system ports -- GUI applications and VNC sessions - -### Both together - -Use agentOS with [external sandboxes](/docs/sandboxes) for workflows that need both: - -- Agent runs in the agentOS VM with full access to bindings and permissions -- Sandbox spins up on demand for heavy tasks -- Sandbox filesystem is mounted into the VM as a native directory -- Agent reads and writes sandbox files the same way it reads local files \ No newline at end of file diff --git a/website/public/docs/docs/workflows.md b/website/public/docs/docs/workflows.md deleted file mode 100644 index 84eb098e85..0000000000 --- a/website/public/docs/docs/workflows.md +++ /dev/null @@ -1,25 +0,0 @@ -# Workflows & Graphs - -Orchestrate multi-step agent tasks with durable workflows. - -Orchestrate multi-step agent tasks with durable workflows that survive crashes and restarts. Build them with RivetKit's `workflow()` run handler, where each `ctx.step()` is recorded, retried, and resumed independently, and the output of one step can feed into the next. - -## Basic workflow - -A workflow is the durable `run` handler of an actor. Wrap it in `workflow()` and drive a multi-step agent task as an ordered series of steps: clone the repo, let an agent fix the bug, then run the tests. Each actor instance is one workflow run initialized with creation input, so no application queue is required. - -Session creation and prompting happen within the step that uses them, so a session never has to outlive the work it backs (sessions are ephemeral and would not survive a replay). Steps reach the agentOS VM, a separate actor, through `ctx.client()`. - -## Agent chaining - -Output of one agent session feeds into the next. Each session is created and completed within its own step, and data passes between steps through the VM filesystem (a review file) and step return values. - -## Recommendations - -- Build the actor's `run` handler with `workflow()` so each `ctx.step()` is durable: recorded, retried, and resumed independently across crashes and restarts. -- Keep step names stable across code changes. Renaming a step breaks replay for in-progress workflows. -- Create and close sessions within the step that uses them. Sessions are ephemeral, so keep their lifetime scoped to one unit of work. -- Pass data between steps via the filesystem or step return values, not session state. -- Keep `state` changes and other actor-local side effects inside `ctx.step()` callbacks; use non-step workflow code only for orchestration. -- Reach the agentOS VM, a separate actor, from inside a step with `ctx.client()`. -- See [Workflows](https://rivet.dev/docs/actors/workflows) for the full workflow API reference including timers, joins, and races. \ No newline at end of file diff --git a/website/public/favicon.svg b/website/public/favicon.svg deleted file mode 100644 index 33655f670f..0000000000 --- a/website/public/favicon.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - OS - - - - - diff --git a/website/public/fonts/jetbrains-mono/JetBrainsMono-Variable-latin.woff2 b/website/public/fonts/jetbrains-mono/JetBrainsMono-Variable-latin.woff2 deleted file mode 100644 index c3f0666ea8..0000000000 Binary files a/website/public/fonts/jetbrains-mono/JetBrainsMono-Variable-latin.woff2 and /dev/null differ diff --git a/website/public/fonts/manrope/Manrope-Variable-latin.woff2 b/website/public/fonts/manrope/Manrope-Variable-latin.woff2 deleted file mode 100644 index 9d7abb17d3..0000000000 Binary files a/website/public/fonts/manrope/Manrope-Variable-latin.woff2 and /dev/null differ diff --git a/website/public/grim-hand.png b/website/public/grim-hand.png deleted file mode 100644 index d9ea0f17b1..0000000000 Binary files a/website/public/grim-hand.png and /dev/null differ diff --git a/website/public/grim-reaper.png b/website/public/grim-reaper.png deleted file mode 100644 index 4e49b44042..0000000000 Binary files a/website/public/grim-reaper.png and /dev/null differ diff --git a/website/public/hero-bg.jpg b/website/public/hero-bg.jpg deleted file mode 100644 index a0ae979bf5..0000000000 Binary files a/website/public/hero-bg.jpg and /dev/null differ diff --git a/website/public/images/agent-logos/claude-code.svg b/website/public/images/agent-logos/claude-code.svg deleted file mode 100644 index 879ad81261..0000000000 --- a/website/public/images/agent-logos/claude-code.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/website/public/images/agent-logos/codex.svg b/website/public/images/agent-logos/codex.svg deleted file mode 100644 index 02921c7e88..0000000000 --- a/website/public/images/agent-logos/codex.svg +++ /dev/null @@ -1,2 +0,0 @@ - -OpenAI icon \ No newline at end of file diff --git a/website/public/images/agent-logos/opencode.svg b/website/public/images/agent-logos/opencode.svg deleted file mode 100644 index b79140a507..0000000000 --- a/website/public/images/agent-logos/opencode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/website/public/images/agent-logos/pi.svg b/website/public/images/agent-logos/pi.svg deleted file mode 100644 index 0369327841..0000000000 --- a/website/public/images/agent-logos/pi.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/website/public/images/agent-os/agentos-hero-logo-animated.svg b/website/public/images/agent-os/agentos-hero-logo-animated.svg deleted file mode 100644 index 2433b74814..0000000000 --- a/website/public/images/agent-os/agentos-hero-logo-animated.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - diff --git a/website/public/images/agent-os/agentos-hero-logo.svg b/website/public/images/agent-os/agentos-hero-logo.svg deleted file mode 100644 index e3443834cc..0000000000 --- a/website/public/images/agent-os/agentos-hero-logo.svg +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - diff --git a/website/public/images/agent-os/agentos-logo-ink.svg b/website/public/images/agent-os/agentos-logo-ink.svg deleted file mode 100644 index ae411ec6c8..0000000000 --- a/website/public/images/agent-os/agentos-logo-ink.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - OS - - - - - diff --git a/website/public/images/agent-os/agentos-logo.svg b/website/public/images/agent-os/agentos-logo.svg deleted file mode 100644 index f6cd8e32ca..0000000000 --- a/website/public/images/agent-os/agentos-logo.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - OS - - - - - diff --git a/website/public/images/agent-os/v8-logo.svg b/website/public/images/agent-os/v8-logo.svg deleted file mode 100644 index b8692f348a..0000000000 --- a/website/public/images/agent-os/v8-logo.svg +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/website/public/images/agent-os/webassembly-logo.svg b/website/public/images/agent-os/webassembly-logo.svg deleted file mode 100644 index f2d67d77a3..0000000000 --- a/website/public/images/agent-os/webassembly-logo.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/website/public/images/architecture/javascript-executor-readiness-state-dark.svg b/website/public/images/architecture/javascript-executor-readiness-state-dark.svg deleted file mode 100644 index c9c0e9acfd..0000000000 --- a/website/public/images/architecture/javascript-executor-readiness-state-dark.svg +++ /dev/null @@ -1,146 +0,0 @@ - - - AgentOS coalesced readiness state machine - Dark-mode state machine demonstrating flags, per-capability revisions, per-VM wake epochs, acknowledgement races, and JavaScript backpressure. - - - - - - - - 4 · Coalescing — revisions are counters, not queued messages - Example for capability 42. One per-handle map entry survives races; one per-VM epoch identifies the currently outstanding doorbell. - - - Timeline: three readiness publications become at most two wakes - - - - 0 - Idle - queue = [] - flags = ∅ - revision = 7 - wake = Idle - No task or thread is spinning. - - - 1 - First Data event - queue = [chunk A] - flags = READABLE - revision = 8 - wake = Outstanding(11) - Enqueue ReadyWake(epoch 11). - - - 2 - More Data before drain - queue = [chunk A, chunk B] - flags = READABLE - revision = 9 - wake = Outstanding(11) - No second wake: already outstanding. - - - 3 - V8 takes batch - epoch = 11 - cap = 42 - flags = READABLE - observedRevision = 9 - This is a snapshot, not removal. - - - 4 - Race: chunk C - queue += chunk C - flags = READABLE - revision = 10 - wake = Outstanding(11) - Still no extra wake yet. - - - - - - - - - 5 - V8 acknowledges what it observed - complete_wake(epoch=11, observedRevision=9) - Current revision is 10, so flags are not cleared. - An old acknowledgement cannot erase newer work. - - - 6 - Broker atomically rearms - wake: Outstanding(11) → Idle - work remains → Outstanding(12) - Exactly one replacement wake is enqueued. - - - 7 - Next drain catches up - batch(epoch=12, revision=10) - ack revision=10 → clear READABLE - If no other work exists, wake returns to Idle. - - - - - - What is bounded? - • ReadyState has at most one entry per admitted capability. - • The wake mailbox has capacity one and state permits one queued/in-flight epoch. - • The socket completion queue is bounded by event count and charged bytes. - • ready_batch copies at most the configured work quantum. - - - What is not a queue? - • Revision 8 → 9 → 10 is one integer field being updated, not three queued revisions. - • READABLE is one level bit, not one event per packet or byte chunk. - • Epoch 11 identifies one wake cycle; it does not enumerate the socket events. - • The wake never owns payload bytes, so wake coalescing cannot lose data. - - - - Backpressure state: JavaScript controls whether the Tokio reader is allowed to read again - - Guest Readable buffer - reaches its high-water mark - Readable.push(bytes) === false - applicationReadDemand = false - bridge: SetReadInterest(false) - This is stream backpressure, not unref(). - - - Broker + socket capability pause - clear/suppress READABLE delivery - applicationReadInterest = false - reader waits on Notify - No repeated level-ready spin or wake storm. - - - Where bytes wait - bounded already-read completion state - plus OS receive buffer - plus sender-side TCP flow control - No additional readiness messages accumulate. - - - When JS needs more - _read() - SetReadInterest(true) - wake reader + republish if known - The bounded cycle begins again. - - - - - - diff --git a/website/public/images/architecture/javascript-executor-wakeup-sequence-dark.svg b/website/public/images/architecture/javascript-executor-wakeup-sequence-dark.svg deleted file mode 100644 index fad63f61f4..0000000000 --- a/website/public/images/architecture/javascript-executor-wakeup-sequence-dark.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - AgentOS socket readiness to V8 sequence - Dark-mode sequence diagram showing how a Tokio socket task stores data, publishes readiness, wakes the separate V8 executor, and causes JavaScript to drain the data. - - - - - - - - - 2 · One TCP read — exact wake-up and call-into-V8 sequence - The wake is only a doorbell. The actual bytes take a separate path and are fetched by JavaScript after V8 is awake. - - - - OS kernelTCP + epoll - - Tokio socket taskshared runtime worker - - Completion queuebounded, contains bytes - - ReadyState brokerflags + revisions - - V8 executor threadowns isolate + selector - - Guest JS NetSocketreadiness target + Duplex - - - - - - - - - - A. Tokio discovers work and stores it - 1 - - fd readable → Tokio Waker schedules socket future - 2 - - bounded try_read() turn - - bytes: [48 65 6c 6c 6f] - 3 - - send Data(bytes, accounting reservation) - If full, this task stops reading; the bytes remain in the kernel. - - - B. The same publisher rings one coalesced doorbell - 4 - - publish(cap=42, gen=3, READABLE) - - ReadyState[42].flags |= READABLE - ReadyState[42].revision += 1 - Repeated publications overwrite/merge this entry. - 5 - - ReadyWake { generation, epoch } - Internally: Tokio MPSC[1] staging → immediate crossbeam[1] transfer. - No bytes, socket event, packet count, or revision list is in the wake. - - - C. The V8 thread notices the wake and enters JavaScript itself - - crossbeam Select unblocks - Tokio did not enter V8 - 6 - - take_batch(epoch) - - [(cap=42, gen=3, flags=R, revision=9)] - 7 - - V8 Function::call(_agentOSReadyDispatch, 42, 3, R) - - JS Map lookup → wakeSocketBridgeReads() - Queues a JS microtask; still on the V8 thread. - - - D. JavaScript fetches bytes over a call-specific bridge response - 8 - - _netSocketReadRaw.applySync(socketId) - V8 executor blocks only itself while the registered call waiter settles. - - dequeue Data → direct response → actual bytes - 9 - Readable.push(bytes) - 10 - - complete_batch(epoch, observed revisions) - Clears only unchanged observations; newer revisions cause a replacement wake. - - - Important: the readiness path wakes V8; the bridge read path transports bytes. They are separate so millions of readiness signals cannot become millions of queued payload messages. - diff --git a/website/public/images/frameworks/eve-icon.svg b/website/public/images/frameworks/eve-icon.svg deleted file mode 100644 index a55dfe6730..0000000000 --- a/website/public/images/frameworks/eve-icon.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/website/public/images/frameworks/eve.svg b/website/public/images/frameworks/eve.svg deleted file mode 100644 index c701416c96..0000000000 --- a/website/public/images/frameworks/eve.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/website/public/images/frameworks/flue.svg b/website/public/images/frameworks/flue.svg deleted file mode 100644 index ea7569fc00..0000000000 --- a/website/public/images/frameworks/flue.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/website/public/images/frameworks/rivet.svg b/website/public/images/frameworks/rivet.svg deleted file mode 100644 index bf46b8a3bf..0000000000 --- a/website/public/images/frameworks/rivet.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/website/public/images/rust.svg b/website/public/images/rust.svg deleted file mode 100644 index faa8c3a347..0000000000 --- a/website/public/images/rust.svg +++ /dev/null @@ -1 +0,0 @@ -Rust \ No newline at end of file diff --git a/website/public/logos/sandbox-agent/claude.svg b/website/public/logos/sandbox-agent/claude.svg deleted file mode 100644 index 879ad81261..0000000000 --- a/website/public/logos/sandbox-agent/claude.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/website/public/logos/sandbox-agent/cloudflare.svg b/website/public/logos/sandbox-agent/cloudflare.svg deleted file mode 100644 index 71921a3f8c..0000000000 --- a/website/public/logos/sandbox-agent/cloudflare.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/website/public/logos/sandbox-agent/daytona.svg b/website/public/logos/sandbox-agent/daytona.svg deleted file mode 100644 index f56f900934..0000000000 --- a/website/public/logos/sandbox-agent/daytona.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/website/public/logos/sandbox-agent/docker.svg b/website/public/logos/sandbox-agent/docker.svg deleted file mode 100644 index 44de5dbd0c..0000000000 --- a/website/public/logos/sandbox-agent/docker.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/website/public/logos/sandbox-agent/e2b.svg b/website/public/logos/sandbox-agent/e2b.svg deleted file mode 100644 index db48b9bef8..0000000000 --- a/website/public/logos/sandbox-agent/e2b.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/website/public/logos/sandbox-agent/openai.svg b/website/public/logos/sandbox-agent/openai.svg deleted file mode 100644 index 02921c7e88..0000000000 --- a/website/public/logos/sandbox-agent/openai.svg +++ /dev/null @@ -1,2 +0,0 @@ - -OpenAI icon \ No newline at end of file diff --git a/website/public/logos/sandbox-agent/opencode.svg b/website/public/logos/sandbox-agent/opencode.svg deleted file mode 100644 index c2404f26f5..0000000000 --- a/website/public/logos/sandbox-agent/opencode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/website/public/logos/sandbox-agent/pi.svg b/website/public/logos/sandbox-agent/pi.svg deleted file mode 100644 index ed14b63805..0000000000 --- a/website/public/logos/sandbox-agent/pi.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/website/public/logos/sandbox-agent/vercel.svg b/website/public/logos/sandbox-agent/vercel.svg deleted file mode 100644 index faa3cbe9a7..0000000000 --- a/website/public/logos/sandbox-agent/vercel.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/website/public/og.png b/website/public/og.png deleted file mode 100644 index a6242cbd53..0000000000 Binary files a/website/public/og.png and /dev/null differ diff --git a/website/public/rivet-icon.svg b/website/public/rivet-icon.svg deleted file mode 100644 index 287c425791..0000000000 --- a/website/public/rivet-icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/website/public/rivet-logo-text-white.svg b/website/public/rivet-logo-text-white.svg deleted file mode 100644 index fcb2f05b82..0000000000 --- a/website/public/rivet-logo-text-white.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/website/public/robots.txt b/website/public/robots.txt deleted file mode 100644 index d2c5dd2643..0000000000 --- a/website/public/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -User-agent: * -Allow: / - -Sitemap: https://sandbox-agent.dev/sitemap-index.xml diff --git a/website/public/sandbox-agent-logo.svg b/website/public/sandbox-agent-logo.svg deleted file mode 100644 index f4704bd583..0000000000 --- a/website/public/sandbox-agent-logo.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/website/src/assets/logo.svg b/website/src/assets/logo.svg deleted file mode 100644 index cd27d6b8b2..0000000000 --- a/website/src/assets/logo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/website/src/components/AgentOSHeroLogo.astro b/website/src/components/AgentOSHeroLogo.astro deleted file mode 100644 index c75ba4a650..0000000000 --- a/website/src/components/AgentOSHeroLogo.astro +++ /dev/null @@ -1,25 +0,0 @@ ---- -/** - * Animated agentOS wordmark for the docs overview hero. Wraps the React - * AnimatedAgentOSLogo (which fetches /images/agent-os/agentos-hero-logo-animated.svg - * and animates its stroke/text/os layers) as a hydrated island. The docs pages - * have no Tailwind utilities, so sizing is provided via a global style here - * rather than the component's Tailwind className. - */ -import { AnimatedAgentOSLogo } from "./marketing/solutions/AgentOSPage"; ---- - - - - diff --git a/website/src/components/DeployTargets.astro b/website/src/components/DeployTargets.astro deleted file mode 100644 index 63d10ef075..0000000000 --- a/website/src/components/DeployTargets.astro +++ /dev/null @@ -1,103 +0,0 @@ ---- -// Deploy target cards for the docs. The target list is shared with the -// registry page's Deploy section via src/data/deploy-targets.ts. -import { DEPLOY_TARGETS } from "../data/deploy-targets"; ---- - -
- { - DEPLOY_TARGETS.map((target) => ( - - - - {target.title} - - - - )) - } -
- - diff --git a/website/src/components/Footer.tsx b/website/src/components/Footer.tsx deleted file mode 100644 index b4d9af226c..0000000000 --- a/website/src/components/Footer.tsx +++ /dev/null @@ -1,119 +0,0 @@ -"use client"; - -import { motion } from "framer-motion"; - -const footer = { - product: [ - { name: "Use Cases", href: "/use-cases" }, - { name: "Registry", href: "/registry" }, - ], - developers: [ - { name: "Documentation", href: "/docs" }, - { name: "Changelog", href: "https://github.com/rivet-dev/agentos/releases" }, - { name: "GitHub", href: "https://github.com/rivet-dev/agentos" }, - ], - social: [ - { - name: "Discord", - href: "https://rivet.dev/discord", - icon: ( - - - - ), - }, - { - name: "GitHub", - href: "https://github.com/rivet-dev/agentos", - icon: ( - - - - ), - }, - { - name: "Twitter", - href: "https://x.com/rivet_dev", - icon: ( - - - - ), - }, - ], -}; - -export function Footer() { - return ( -
-
-
- - - agentOS - -

The open-source virtual operating system for agents.

-
- {footer.social.map((item) => ( - - {item.name} - {item.icon} - - ))} -
-
- -
- -

Product

- -
- - -

Developers

- -
-
-
- - -

© {new Date().getFullYear()} agentOS. Apache 2.0 licensed.

-
-
-
- ); -} diff --git a/website/src/components/GitHubStars.tsx b/website/src/components/GitHubStars.tsx deleted file mode 100644 index b8b7a24459..0000000000 --- a/website/src/components/GitHubStars.tsx +++ /dev/null @@ -1,60 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; - -interface GitHubStarsProps extends React.AnchorHTMLAttributes { - repo?: string; -} - -function formatNumber(num: number): string { - if (num >= 1000) { - return `${(num / 1000).toFixed(1)}k`; - } - return num.toString(); -} - -export function GitHubStars({ repo = "rivet-dev/agentos", className, ...props }: GitHubStarsProps) { - const [stars, setStars] = useState(null); - - useEffect(() => { - const cacheKey = `github-stars-${repo}`; - const cachedData = sessionStorage.getItem(cacheKey); - - if (cachedData) { - const { stars: cachedStars, timestamp } = JSON.parse(cachedData); - if (Date.now() - timestamp < 5 * 60 * 1000) { - setStars(cachedStars); - return; - } - } - - fetch(`https://api.github.com/repos/${repo}`) - .then((response) => { - if (!response.ok) throw new Error("Failed to fetch"); - return response.json(); - }) - .then((data) => { - const newStars = data.stargazers_count; - setStars(newStars); - sessionStorage.setItem( - cacheKey, - JSON.stringify({ - stars: newStars, - timestamp: Date.now(), - }), - ); - }) - .catch((err) => { - console.error("Failed to fetch stars", err); - }); - }, [repo]); - - return ( - - - - - {stars ? `${formatNumber(stars)} Stars` : "GitHub"} - - ); -} diff --git a/website/src/components/Navigation.tsx b/website/src/components/Navigation.tsx deleted file mode 100644 index e4043011cb..0000000000 --- a/website/src/components/Navigation.tsx +++ /dev/null @@ -1,195 +0,0 @@ -"use client"; - -import { useState, useEffect } from "react"; -import { Menu, X } from "lucide-react"; -import { GitHubStars } from "./GitHubStars"; -import { registry } from "../data/registry"; - -function DiscordIcon({ className }: { className?: string }) { - return ( - - ); -} - -const NAV_LINKS: { href: string; label: string; badge?: number }[] = [ - { href: "/docs", label: "Documentation" }, - { href: "/cookbooks", label: "Cookbooks" }, - { href: "/use-cases", label: "Use Cases" }, - { href: "/registry", label: "Registry", badge: registry.length }, - { href: "/docs/deployment", label: "Deploy" }, -]; - -function NavBadge({ count }: { count: number }) { - return ( - - {count} - - ); -} - -function NavItem({ href, children, badge }: { href: string; children: React.ReactNode; badge?: number }) { - return ( - - {children} - {badge != null && } - - ); -} - -export function Navigation({ revealLogoOnScroll = false }: { revealLogoOnScroll?: boolean }) { - const [mobileMenuOpen, setMobileMenuOpen] = useState(false); - const [isScrolled, setIsScrolled] = useState(false); - // On pages with a hero logo, keep the nav logo hidden until the hero logo - // scrolls up behind the nav. Elsewhere it's always visible. - const [logoVisible, setLogoVisible] = useState(!revealLogoOnScroll); - - useEffect(() => { - const handleScroll = () => setIsScrolled(window.scrollY > 20); - handleScroll(); - window.addEventListener("scroll", handleScroll); - return () => window.removeEventListener("scroll", handleScroll); - }, []); - - useEffect(() => { - if (!revealLogoOnScroll) return; - const heroLogo = document.getElementById("hero-logo"); - if (!heroLogo) { - setLogoVisible(true); // fail open: no hero logo on this page → always show - return; - } - const observer = new IntersectionObserver( - ([entry]) => setLogoVisible(!entry.isIntersecting), - // Negative top margin (~nav height) so the crossover lands at the nav - // rather than the very top edge of the viewport. - { rootMargin: "-80px 0px 0px 0px" }, - ); - observer.observe(heroLogo); - return () => observer.disconnect(); - }, [revealLogoOnScroll]); - - return ( -
-
- - - {mobileMenuOpen && ( - - )} -
- ); -} diff --git a/website/src/components/faq/FaqJsonLd.astro b/website/src/components/faq/FaqJsonLd.astro deleted file mode 100644 index cba8e584f2..0000000000 --- a/website/src/components/faq/FaqJsonLd.astro +++ /dev/null @@ -1,25 +0,0 @@ ---- -// Emits FAQPage JSON-LD for a page's FAQ items. Usage rules: -// - At most one FaqJsonLd per page, and only from .astro pages, so each URL -// has exactly one FAQPage block. -// - The same items array must also be rendered visibly on the page through -// FaqList or FaqSection. Google requires schema content to be visible. -// - FAQPage coexists with Product, Article, and other schema types as sibling -// script tags. Never nest it inside another schema object. -// - Since August 2023 Google shows FAQ rich results only for authoritative -// government and health sites. The value here is long-tail content and -// AI-answer extraction; the schema is nearly free since it derives from the -// same data module as the visible rendering. -import { faqPageSchema, type FaqItem } from '../../data/faqs/types'; -import { jsonLdString } from '../../lib/jsonLd'; - -interface Props { - items: FaqItem[]; -} - -const { items } = Astro.props; - -const json = jsonLdString(faqPageSchema(items)); ---- - - - - - - - - - diff --git a/website/src/lib/highlight-code.ts b/website/src/lib/highlight-code.ts deleted file mode 100644 index 56d49097c5..0000000000 --- a/website/src/lib/highlight-code.ts +++ /dev/null @@ -1,173 +0,0 @@ -// Dependency-free syntax highlighter for the marketing hero code tabs. -// -// The original Rivet site rendered these snippets with Shiki at build time and -// styled the resulting `.shiki` / `.line` markup. Shiki is not resolvable from -// this package, so we tokenize the (TS/JS) source ourselves and emit the same -// `.shiki` > `.line` structure with inline-colored token spans. The hero code -// block styles the container (`[&_.shiki]:!bg-transparent`, muted base text), so -// only the token foregrounds matter here. -// -// Kept async + same signature as the prior `highlightCodeHtml` so callers -// (Astro pages) do not change. - -function escapeHtml(code: string): string { - return code - .replace(/&/g, "&") - .replace(//g, ">"); -} - -// Light-theme palette: purple keywords, orange strings, gray-italic comments, -// blue function calls. Tuned to read on the light (`bg-zinc-50`) code block. -const STYLES: Record = { - comment: "color:#8b949e;font-style:italic", - keyword: "color:#8250df", - string: "color:#b45309", - number: "color:#0550ae", - fn: "color:#0550ae", -}; - -const KEYWORDS = new Set([ - "import", "export", "from", "const", "let", "var", "await", "async", - "function", "return", "new", "class", "extends", "implements", "interface", - "type", "enum", "if", "else", "for", "while", "do", "switch", "case", - "break", "continue", "default", "try", "catch", "finally", "throw", - "typeof", "instanceof", "in", "of", "void", "yield", "this", "super", - "static", "public", "private", "protected", "readonly", "as", "satisfies", - "namespace", "declare", "true", "false", "null", "undefined", -]); - -interface Token { - type: keyof typeof STYLES | "text"; - value: string; -} - -function tokenize(code: string): Token[] { - const tokens: Token[] = []; - const n = code.length; - let i = 0; - let text = ""; - - const flushText = () => { - if (text) { - tokens.push({ type: "text", value: text }); - text = ""; - } - }; - - const isIdentStart = (c: string) => /[A-Za-z_$]/.test(c); - const isIdent = (c: string) => /[\w$]/.test(c); - - while (i < n) { - const c = code[i]; - const next = code[i + 1]; - - // Line comment - if (c === "/" && next === "/") { - flushText(); - let j = i + 2; - while (j < n && code[j] !== "\n") j++; - tokens.push({ type: "comment", value: code.slice(i, j) }); - i = j; - continue; - } - - // Block comment - if (c === "/" && next === "*") { - flushText(); - let j = i + 2; - while (j < n && !(code[j] === "*" && code[j + 1] === "/")) j++; - j = Math.min(n, j + 2); - tokens.push({ type: "comment", value: code.slice(i, j) }); - i = j; - continue; - } - - // Strings and template literals - if (c === '"' || c === "'" || c === "`") { - flushText(); - const quote = c; - let j = i + 1; - while (j < n) { - if (code[j] === "\\") { - j += 2; - continue; - } - if (code[j] === quote) { - j++; - break; - } - j++; - } - tokens.push({ type: "string", value: code.slice(i, j) }); - i = j; - continue; - } - - // Numbers - if (/[0-9]/.test(c) && !(text && isIdent(text[text.length - 1]))) { - flushText(); - let j = i; - while (j < n && /[0-9._a-fxA-FXn]/.test(code[j])) j++; - tokens.push({ type: "number", value: code.slice(i, j) }); - i = j; - continue; - } - - // Identifiers / keywords / function calls - if (isIdentStart(c)) { - flushText(); - let j = i + 1; - while (j < n && isIdent(code[j])) j++; - const word = code.slice(i, j); - if (KEYWORDS.has(word)) { - tokens.push({ type: "keyword", value: word }); - } else { - // Function call if the next non-space char is "(" - let k = j; - while (k < n && (code[k] === " " || code[k] === "\t")) k++; - tokens.push({ type: code[k] === "(" ? "fn" : "text", value: word }); - } - i = j; - continue; - } - - text += c; - i++; - } - - flushText(); - return tokens; -} - -function renderTokens(tokens: Token[]): string { - // Build per-line markup, splitting token values that span newlines so each - // `.line` stays self-contained (the container styles `.line` for wrapping). - const lines: string[][] = [[]]; - - for (const token of tokens) { - const parts = token.value.split("\n"); - parts.forEach((part, idx) => { - if (idx > 0) lines.push([]); - if (part === "") return; - const escaped = escapeHtml(part); - const style = token.type === "text" ? undefined : STYLES[token.type]; - lines[lines.length - 1].push( - style ? `${escaped}` : escaped, - ); - }); - } - - return lines - .map((parts) => `${parts.join("") || " "}`) - .join("\n"); -} - -export async function highlightCodeHtml( - code: string, - _lang = "ts", - _theme?: string, -): Promise { - const html = renderTokens(tokenize(code)); - return `
${html}
`; -} diff --git a/website/src/lib/jsonLd.ts b/website/src/lib/jsonLd.ts deleted file mode 100644 index 2829117086..0000000000 --- a/website/src/lib/jsonLd.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Serialize a schema object for injection via set:html inside an inline -// diff --git a/website/src/pages/registry/index.astro b/website/src/pages/registry/index.astro deleted file mode 100644 index 75ade85a94..0000000000 --- a/website/src/pages/registry/index.astro +++ /dev/null @@ -1,48 +0,0 @@ ---- -import Layout from "../../layouts/Layout.astro"; -import { Navigation } from "../../components/Navigation"; -import { Footer } from "../../components/Footer"; -import RegistryPageClient from "../../components/marketing/registry/RegistryPageClient"; -import type { RegistryCardEntry } from "../../components/marketing/registry/RegistryPageClient"; -import { registry } from "../../data/registry"; -import { HERO_H1_CLASS } from "../../components/marketing/typography"; - -// Slim each entry down to the fields the storefront renders so multi-line -// config examples never ship in the island's serialized props. -const entries: RegistryCardEntry[] = registry.map((entry) => ({ - slug: entry.slug, - title: entry.title, - description: entry.description, - types: entry.types, - status: entry.status, - featured: entry.featured, - beta: entry.beta, - icon: entry.icon, - image: entry.image, - href: entry.status === "external" ? entry.href : undefined, -})); ---- - - - -
-
-
-

- agentOS Registry -

-

- Agents, file systems, browsers, and software packages for agentOS. -

-
-
- -
- -
-
-