agentos / crates
CLAUDE.md4.9k starsChanged 45 days agoApache-2.0View on GitHub
The Rust sidecar implements the kernel: virtual filesystem, process table, socket table, pipe/PTY management, and permission system. Guest code sees a self-contained OS and must never interact with the host directly. The kernel orchestrates three execution environments: ALL guest code MUST execute inside the kernel with ZERO host escapes. No runtime may spawn unsandboxed host processes, touch real host filesystems, open real network sockets, or call real Node.js builtins. Every syscall goes through the kernel. This is the single most…
- Reads credentials
2 other projects use a version of this.
Trending
Steady talk.thin dataabout the whole repository
Most recently taken up by
- rivet-dev/rivetkitword for word, first seen Oct 9, 2026
- rivet-dev/agent-osword for word, first seen Oct 8, 2026
Who's talking about rivet-dev/agentos
- @rusttrending.bsky.social“rivet-dev / agentos: A faster, lighter, cheaper alternative to sandboxes. Run any coding agent inside an …”Bluesky · Jun 27, 2026 · 1 likes
- @github-trending-rs.bsky.social“📦 rivet-dev / agentos ⭐ 3,278 (+52) 🗒 Rust A faster, lighter, cheaper alternative to sandboxes. Run any …”Bluesky · Jun 27, 2026 · 1 likes
- swcstudiospace/realm“build(deps): bump @rivet-dev/agentos-core from 0.4.4 to 0.4.6”GitHub · Nov 5, 2026
- greyhaven-ai/autocontext“chore(deps): bump the typescript-versions group in /ts with 13 updates”GitHub · Oct 23, 2026
- joshyorko/actions“research: test disposable V8/WASM Code Mode against existing Actions data and execution contracts”GitHub · Oct 15, 2026
The biggest 5 of 8 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 8
Talked about on GitHub and Bluesky (8 times).
On GitHub · 6
- Nov 5, 2026build(deps): bump @rivet-dev/agentos-core from 0.4.4 to 0.4.6 — swcstudiospace/realm0 reactions
- Oct 23, 2026chore(deps): bump the typescript-versions group in /ts with 13 updates — greyhaven-ai/autocontext0 reactions
- Oct 15, 2026research: test disposable V8/WASM Code Mode against existing Actions data and execution contracts — joshyorko/actions0 reactions
- Sep 7, 2026fix(post): cite rivet-dev/agentos for POST-20260907-000160 — Interchouette/itcy-publications0 reactions
- Jul 29, 2026Secure tool execution, good choice to manage what agent can do — kanthorlabs/kanthord0 reactions
1 more on GitHub
- Jul 8, 2026Sandboxing — P0u4a/nova0 reactions
On Bluesky · 2
- Jun 27, 2026rivet-dev / agentos: A faster, lighter, cheaper alternative to sandboxes. Run any coding agent inside an isolated Linux VM, with agent… — @rusttrending.bsky.social1 likes and repost
- Jun 27, 2026📦 rivet-dev / agentos ⭐ 3,278 (+52) 🗒 Rust A faster, lighter, cheaper alternative to sandboxes. Run any coding agent inside an isolated… — @github-trending-rs.bsky.social1 likes and repost
Other versions2 projects use a version of this.
Word for word · 2
- rivet-dev/agent-os★ 4.9k100% same
- rivet-dev/rivetkit★ 4.9k100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository8 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- docs/CLAUDE.mdCLAUDE.md
- packages/CLAUDE.mdCLAUDE.md
- launch-graphicsSkill
- publish-registrySkill
- release-previewSkill
- releaseSkill
- sanity-checkSkill
The file
We split this CLAUDE.md into the rules it gives an agent
4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 124
Keep crates/sidecar/tests/builtin_conformance.rs as one top-level builtin_conformance_cases test that forks per-case subprocesses via …
- Very specific: line 126
Run scoped tests: cargo test -p agentos-sidecar -- test_name_filter or cargo test -p agentos-sidecar --lib (lib unit tests only, skip …
- Very specific: line 127
Never run bare cargo test -p agentos-sidecar without a filter -- integration tests spawn real processes and can hang.
- Very specific: line 131
Do not hide first-party Rust coverage behind #[ignore].
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
agentOS Rust Crates
The Rust sidecar implements the kernel: virtual filesystem, process table, socket table, pipe/PTY management, and permission system. Guest code sees a self-contained OS and must never interact with the host directly.
The kernel orchestrates three execution environments:
- WASM processes -- POSIX utilities (coreutils, sh, grep, etc.) compiled to WebAssembly, running within the sidecar's managed runtime.
- Node.js (V8 isolates) -- JS/TS executes inside isolated V8 contexts managed by the sidecar's execution engine. All Node.js builtin modules (
fs,net,child_process,dns,http,os, etc.) are kernel-backed polyfills that route through the kernel VFS, socket table, and process table via synchronous RPC. Module loading is intercepted so guest code never touches real host APIs. ⚠️ CURRENTLY BROKEN: The execution engine currently spawns real hostnodechild processes instead of V8 isolates, and most builtins fall through to real host modules. This is being actively fixed. The complete working polyfill code from the original@agentospackages has been recovered to~/.agents/recovery/agentos/(source repo:/home/nathan/agentos-1/). Seecrates/execution/CLAUDE.mdfor the gap table and recovery file list. - Python (Pyodide) -- CPython compiled to WASM via Pyodide, with kernel-backed file/network I/O.
ALL guest code MUST execute inside the kernel with ZERO host escapes. No runtime may spawn unsandboxed host processes, touch real host filesystems, open real network sockets, or call real Node.js builtins. Every syscall goes through the kernel. This is the single most important architectural invariant. Any path where guest code reaches the real host is a critical security violation.
NEVER use Command::new("node") for guest code execution. Guest JavaScript runs inside V8 isolates (crates/v8-runtime/), not real Node.js processes. Do NOT add execution mode flags, host fallback paths, or "legacy node mode" — even temporarily, even behind a feature flag. If tests fail because they were written for the old host-process model, fix or delete the tests.
Virtualization Invariants
These are hard rules with no exceptions:
- Every guest syscall goes through the kernel. File reads go through the kernel VFS, not real
node:fs. Network connections go through the kernel socket table, not realnode:net. Process spawning go through the kernel process table, not realnode:child_process. DNS resolution goes through the kernel's DNS resolver, not realnode:dns. There are no shortcuts where guest code touches host resources directly. - No real host builtins. When a guest does
require('fs')orimport net from 'node:net', the module loader must return a kernel-backed polyfill. If no polyfill exists yet, the builtin must be denied (ERR_ACCESS_DENIED). The loader must never fall through to Node.js's default resolution and hand the guest the real host module. - The host is an implementation detail. Guest code should not be able to observe that it is running on a host Node.js process.
process.pidshould be the kernel PID,os.hostname()should be the kernel hostname,fs.readdirSync('/')should show the kernel VFS root.process.cwd()should return the kernel CWD, not a host path.process.envmust not contain internalAGENT_OS_*control variables. Error messages and stack traces must not reveal host filesystem paths.require.resolve()must return guest-visible paths, not host paths. Any host state leaking through to the guest is a bug. - Polyfills are ports, not wrappers. A path-translating shim over real
node:fsis not a polyfill -- it is a wrapper around a host API. A real polyfill implements the API semantics using only kernel primitives (VFS, socket table, process table, pipe manager). The original JavaScript kernel packages, deleted in commit5a43882, had full kernel-backed polyfills forfs,net,http,dns,dgram,child_process, andos. The Rust sidecar must reach the same level of isolation. - Control channels must be out-of-band. The sidecar must not use in-band magic prefixes on stdout/stderr for control signaling (exit codes, metrics, signal registration). Guest code can write these prefixes to inject fake control messages. Use dedicated file descriptors, separate pipes, or a side-channel protocol for all sidecar-internal communication.
- Resource consumption must be bounded. Every guest-allocatable resource must have a configurable limit enforced by the kernel: filesystem total size, inode count, process count, open FDs, pipes, PTYs, sockets, connections. Unbounded allocation from guest input is a DoS vector. The kernel's
ResourceLimitsmust cover all resource types, not just processes and FDs. Sidecar metadata parsing should start fromResourceLimits::default()and only override keys that are actually present; rebuilding the struct from sparse metadata drops default filesystem byte/inode caps. Per-operation memory guards also live inResourceLimits: boundpread,fd_write/fd_pwrite, merged spawnargv/env, andreaddirbatches incrates/kernel/src/kernel.rs, and keep the matchingresource.max_*metadata keys incrates/sidecar/src/service.rsin sync so the limits remain configurable. WASM runtime caps are also carried throughResourceLimits:crates/sidecar/src/service.rsmaps the configuredmax_wasm_*fields into reservedAGENT_OS_WASM_*env keys, andcrates/execution/src/wasm.rsis responsible for enforcing the resulting fuel/memory/stack limits before guest code runs. WebAssembly parser hardening incrates/execution/src/wasm.rsmust stat module files beforefs::read(), cap import/memory section entry counts before iterating them, and bound varuint encodings by byte length so malformed or oversized modules fail closed without parser DoS. - Permission checks must use resolved paths. Whenever the kernel checks permissions on a path, it must resolve symlinks first and check the resolved path. Checking the caller-supplied path and then operating on a symlink-resolved target is a TOCTOU bypass. Similarly,
link()must check permissions on both source and destination. Rule-based static sidecar policies must use explicit["*"]wildcards foroperationsandpaths/patterns; empty arrays are invalid policy input and should be rejected instead of treated as implicit wildcards. - The VM must behave like a standard Linux environment. Agents are written to target Linux. The kernel should implement POSIX semantics faithfully -- correct
errnovalues, proper signal delivery, standard/proclayout, expected filesystem behavior. Deviations from standard Linux behavior cause agent failures and must be documented in the friction log (~/.agents/notes/vm-friction.md). When in doubt, match Linux kernel behavior, not a simplified model.
Key Subsystems
- Virtual filesystem (VFS) -- Layered chunked architecture:
ChunkedVFScomposesFsMetadataStore(directory tree, inodes, chunk mapping) +FsBlockStore(key-value blob store) into aVirtualFileSystem. Tiered storage keeps small files inline in metadata; larger files are split into chunks in the block store. The device layer (/dev/null,/dev/urandom,/dev/pts/*, etc.), proc layer (/proc/[pid]/*), and permission wrapper sit on top. All layers implement theVirtualFileSysteminterface with full POSIX semantics. - Process management -- Kernel-wide process table tracks PIDs across all runtimes. Full POSIX process model: parent/child relationships, process groups, sessions, signals (SIGCHLD, SIGTERM, SIGWINCH), zombie cleanup, and
waitpid. Each process gets its own FD table (0-255) with refcounted file descriptions supporting dup/dup2. Advisoryflockstate should stay kernel-global but be owned by the shared open-file-description (FileDescription.id()), keyed by the opened file identity, and released only when the last refcounted FD closes; dup/fork inheritance must see the same lock while separate opens still conflict. Per-FD status bits such asO_NONBLOCKbelong onFdEntry/ProcessFdTable, while sharedFileDescription.flags()should stay limited to open-file-description semantics such as access mode andO_APPEND;/dev/fd/Nduplication can layer new per-FD flags without mutating the shared description. Host-side liveness probes that must not reap runtime children should usewaitid(..., WNOWAIT | WNOHANG | WEXITED | WSTOPPED | WCONTINUED)rather thanwaitpid; the sidecar uses that non-reaping check before signaling host child PIDs to avoid PID-reuse races. Parent-awarewaitpidstate tracking belongs incrates/kernel/src/process_table.rs: queue stop/continue notifications there, and only letcrates/kernel/src/kernel.rsclean up process resources after an exited child is actually reaped. Process exit handling incrates/kernel/src/process_table.rshas to keep child reparenting, orphaned stopped-process-groupSIGHUP/SIGCONTdelivery, and zombie-awaremax_processesaccounting aligned; changing only one of those paths breaks Linux-style lifecycle semantics. POSIX signal side effects that depend on the calling PID should stay atKernelVmsyscall entrypoints instead of low-level primitives:PipeManageronly reports broken-pipeEPIPE, whilecrates/kernel/src/kernel.rsfd_writeis responsible for turning that into guest-visibleSIGPIPEdelivery. Job-control signal state transitions should stay aligned acrosscrates/kernel/src/process_table.rsandcrates/kernel/src/kernel.rs:ProcessTable::kill(...)ownsSIGSTOP/SIGTSTP/SIGCONTstatus changes andwaitpidnotifications, while PTY resize should emitSIGWINCHfrom theKernelVmentrypoint after the PTY layer reports the foreground process group. - Pipes & PTYs -- Kernel-managed pipes (64KB buffers) enable cross-runtime IPC. PTY master/slave pairs with line discipline support interactive shells.
openShell()allocates a PTY and spawns sh/bash. - Networking -- Socket table manages TCP/UDP/Unix domain sockets. Loopback connections stay entirely in-kernel. External connections delegate to a
HostNetworkAdapter(implemented vianode:net/node:dgramon the host). DNS resolution also goes through the adapter. - Permissions -- Deny-by-default access control. Four permission domains:
fs,network,childProcess,env. Each is a function that returns{allow, reason}. TheallowAllpreset grants everything (used in agentOS). See "Node.js Builtin Permission Model" incrates/execution/CLAUDE.mdfor how these interact with the Node.js builtin interception layer. - Kernel VM configs must opt into broad access explicitly.
KernelVmConfig::new()should stay deny-all by default; tests, browser scaffolds, or other callers that need unrestricted behavior must setconfig.permissions = Permissions::allow_all()themselves. - Browser sidecar workers must mirror execution state into
VmState.kernelbefore or alongside bridge calls. Incrates/sidecar-browser/src/service.rs, create browser-worker executions as kernel virtual processes, wire stdin/stdout/stderr through kernel pipes, and reflect kill/exit/output events back into that kernel state instead of treating the browser sidecar as a bridge-only facade. - Sensitive mount policy is a separate filesystem capability. Kernel mount APIs check normal
fs.writepermission on the mount path, and mounts targeting/,/etc, or/procalso requirefs.mount_sensitive. In the Rust sidecar, internalcreate_vm/configure_vmbootstrap work must temporarily clear guest static permissions and restore the configured policy afterward; otherwise default-deny guest policies block the sidecar's own mount and filesystem reconciliation instead of only guest-visible operations. - Guest-visible mount denial coverage should exercise the restored kernel path, not just
configure_vm(...). Incrates/sidecar/tests/service.rs, useConfigureVmto seed any operator-applied mounts, then callvm.kernel.mount_filesystem(...)under the restored VM policy and assert the mount table is unchanged onEACCES; that keeps bootstrap-mount coverage and guest mount denial coverage separate. - Bridge-backed filesystems must preserve missing-path errno semantics.
js_bridge/host-backed VFS adapters incrates/sidecar/src/bridge.rsneed to map missingstat/lstatlookups toENOENTinstead of a generic bridgeEIO; kernel resource-accounting and create-on-write flows probe missing paths before writes, and treating them as I/O failures breaks new-file creation on mounted host filesystems.
Architecture Rules
- All guest code must execute within the kernel's isolation boundary (WASM or in-kernel isolate). No runtime may escape to a host-native process. If a language runtime requires a JavaScript host (e.g., Emscripten-compiled WASM like Pyodide), the JS host must itself run inside the kernel -- not as a host-side Node.js subprocess. Spawning an unsandboxed host process to run guest code is never acceptable, even as a convenience shortcut.
- Guest code must never touch real host APIs. Every
require('fs'),require('net'),require('child_process'), etc. must return a kernel-backed polyfill. Path-translating wrappers over realnode:fsor realnode:child_processare NOT acceptable. If a polyfill does not exist yet for a builtin, that builtin must be denied at the loader level until one is built. - Native sidecar permission policy has to be available during
create_vm, not justconfigure_vm. Guest env filtering and kernel bootstrap driver registration happen while the VM is being constructed, soAgentOsOptions.permissionsmust be serialized into theCreateVmRequest. ConfigureVm.permissionsis replace-on-write. Omit the field to preserve the VM policy set duringcreate_vm; send an explicit declarative policy object only when the caller intends to replace the current static permission policy.- WASM permission tiers must gate host Node WASI access as well as guest-side preopens. In
crates/execution/src/wasm.rs, keepIsolatedexecutions off--allow-wasientirely, and letReadOnly/ReadWrite/Fulldifferentiate the read/write scope through the guest WASI layer rather than a blanket host flag. sandbox_agentmounts onsandbox-agent@0.4.2only get basic file endpoints (entries,file,mkdir,move,stat) from the HTTP fs API. When the sidecar needs symlink/readlink/realpath/link/chmod/chown/utimes semantics, it must use the remote process API as a fallback and returnENOSYSwhen that helper path is unavailable.sandbox_agentpreadshould prefer HTTPRangeon/v1/fs/file, but older remotes may ignore it and return200 OK. Keep the compatibility path that warns and slices the full response body instead of failing, because the sidecar still has to interoperate with pre-range sandbox-agent servers.- Native sidecar security/audit telemetry should use structured bridge events, not ad hoc strings. In
crates/sidecar/src/service.rs, emit security-relevant records withbridge.emit_structured_event(...)and include atimestampfield plus stable keys such aspolicy,path,source_pid,target_pid, orreasonso tests and downstream aggregation can assert on them directly. - Native mount plugins live under
crates/sidecar/src/plugins/and register throughplugins/mod.rs. Keephost_dir,s3,google_drive, andsandbox_agentthere with shared registration glue, whilebridge.rsonly layers on sidecar-specific in-memory and JS-bridge plugin registration. - The sidecar execution driver's shell-visible builtin commands must mirror the compat runtime surface. Seed
nodeandwasmduringcreate_vm()and preserve them when refreshing/__agentos/commands/*inconfigure_vm(), but do not materialize extra/bin/*runtime stubs such aspythonunless a lower snapshot or installed software explicitly provides them. DirectExecuteRequest { runtime: ... }dispatch still covers runtimes that are not meant to appear in the guest filesystem. - Mounted WASM command directories need both command-map refresh and guest
PATHrefresh. Whencrates/sidecar/src/vm.rsrediscovers/__agentos/commands/*, updatevm.command_guest_pathsand prepend those parent directories intovm.guest_env["PATH"];crates/sidecar/src/execution.rschild-process resolution should searchPATHentries before falling back to/bin,/usr/bin, and/usr/local/bin, or guestchild_process.spawn("sh")/spawn("grep")misses mounted registry commands. - Native-sidecar command resolution must use the caller's effective
PATH, not justvm.guest_env. Incrates/sidecar/src/execution.rs, path-like guest candidates emitted by shells (for example/home/agentos/.pi/agent/bin/printf) should only be treated as executables when the candidate or mapped host file actually exists; if the parent directory came fromPATHbut the file is missing, fall back to the basename so registry command remapping can still findprintf/bash/which. - Native-sidecar WASM commands see the shadow root, so standard guest directories must be seeded there during VM creation. In
crates/sidecar/src/vm.rs, keep/tmp,/var/tmp,/bin,/usr, and the rest of the POSIX bootstrap tree materialized in the shadow root before any WASM command runs, or shell redirection and absolute-path checks will disagree with the kernel VFS (vm.stat("/tmp")works whilesh -c 'echo hi > /tmp/x'fails). - Host filesystem API writes that should be visible to WASM commands must mirror into the shadow root immediately. In
crates/sidecar/src/filesystem.rs,GuestFilesystemOperation::WriteFileneeds to update both the kernel VFS and the VM shadow tree right away, orvm.writeFile("/tmp/x")will succeed while guestsh/cat/lsstill miss the file until some later sync path runs. - Host filesystem API directory creation must mirror into the shadow root too. In
crates/sidecar/src/filesystem.rs,GuestFilesystemOperation::CreateDir/Mkdirneed to create the same directory under the VM shadow tree immediately, or host-backed shells and JavaScript child-process spawns will lose their requested guest cwd even thoughvm.stat()sees the directory in the kernel VFS. - Host filesystem API rename/remove operations must keep the shadow root in sync too. In
crates/sidecar/src/filesystem.rs,GuestFilesystemOperation::Rename,RemoveFile, andRemoveDirneed to move or delete the matching shadow-root path immediately, or the nextexists/statshadow reconciliation can resurrect stale host-side paths back into the kernel. - Guest process writes that land in the sidecar shadow root must be mirrored back into the kernel before process exit completes. In
crates/sidecar/src/execution.rs, sync regular files and symlinks from the shadow-root host tree back into the kernel onActiveExecutionEvent::Exited, or commands likevm.exec("echo hi > /tmp/x && cat /tmp/x")will succeed while a latervm.readFile("/tmp/x")still returnsENOENT. - VM bootstrap must materialize custom root snapshot files into the shadow root, not just standard directories. In
crates/sidecar/src/vm.rs, copy non-bundled snapshot/bootstrap entries into the shadow tree during VM creation, or shell-launched WASM commands likezip /archive.zip /hello.txtwill create new output files successfully while still missing pre-seeded guest inputs that only exist in the kernel snapshot layer. - Top-level sidecar executions must forward the resolved guest cwd into the kernel process too. In
crates/sidecar/src/execution.rs, the firstkernel.spawn_process(...)forexecuterequests cannot hardcode/, orvm.exec(..., { cwd })and relative shell/tool paths drift back to the VM root even when the resolved host cwd is correct. - Bidirectional native sidecar wire frames use signed request IDs.
request/responseframes initiated from TypeScript must keep positiverequest_idvalues, while sidecar-initiatedsidecar_request/sidecar_responseframes must use negative IDs; keep Rust validation, stdio routing, and TS client framing in sync when adding new callback payloads. - Sidecar callback request IDs must start negative even in default state.
SharedSidecarRequestClientshould initialize its counter at-1; a default0request ID causes the firstsidecar_responseto fail protocol validation and leaves callback-driven mounts hanging. - Current-thread stdio framing cannot rely on Tokio reader/writer tasks when callback handlers block on
sidecar_requestresponses. Incrates/native-sidecar/src/stdio.rs, keep framed stdin/stdout I/O on dedicated OS threads so JS-bridge/binding callback traffic can continue while the main sidecar loop waits synchronously for the host response. - Sidecar wire-protocol migrations should preserve the native 4-byte big-endian frame prefix and treat
serde_json::Valuefields as explicit JSON blobs first. Keep framing changes separate from payload-codec changes, and when defining the BARE schema use a temporaryJsonUtf8boundary for dynamic fields (binding schemas/results, mount configs, bridge args) until both Rust and TypeScript can replace them with typed BARE payloads together. - The sidecar BARE wire uses the generated positional tag layout. Do not preserve old hand-assigned union ordinals for byte-for-byte compatibility; client and sidecar are same-version, so Rust/TS codecs should stay self-consistent with
protocol/agentos_sidecar_v1.bareand the generated schema. - Out-of-band process completions still have to flow through the queued process-event pump. If a sidecar feature emits
ProcessEventEnvelopes directly from a background thread instead of viaActiveExecution::poll_event,crates/sidecar/src/execution.rspump_process_events()must drainprocess_event_receiverintopending_process_events; otherwise stdio/native clients never observeprocess_outputorprocess_exitedand host waits hang indefinitely. - Nested JavaScript
child_processpolling must flush queued child execution events before finalizingExited. Incrates/sidecar/src/execution.rs,poll_javascript_child_process()should surface any pending child stdout/stderr/sync-RPC events ahead of the terminal exit event; removing the child as soon asExitedarrives drops fast child output and breaks close-driven spawn conformance. - Descendant JavaScript
child_processsync RPCs must stay recursive. When a nested guest process emitschild_process.spawn/poll/write_stdin/close_stdin/kill, service those RPCs against that process's ownActiveProcess.child_processespath instead of falling through toservice_javascript_sync_rpc(...); otherwise deeper shell or Node launches route into the filesystem RPC fallback and fail with misleadingunsupported JavaScript sync RPC method child_process.*errors. - Sidecar env-hardening tests should assert kernel-owned defaults replace host overrides, not that the keys disappear entirely. In
crates/sidecar/tests/security_hardening.rsand related guest-identity coverage, expect guest-visiblePATH/HOME/PWDto come from the kernel-owned runtime env while internal control vars likeAGENT_OS_*andNODE_SYNC_RPC_*stay hidden fromprocess.env. - Guest shell invocations of
agentos/agentos-*must route through the host-function virtual-process path, not the WASM command path. Incrates/native-sidecar/src/execution.rs, child-process command resolution should only tag host-function commands during the read-only resolve pass, then callresolve_host_function_command(...)once a mutableVmStateis available during spawn so CLI parsing can still read VM files like--json-file. Treating/bin/agentos*as ordinary WASM entrypoints breaks shellexechandoff because those commands are sidecar-dispatched virtual processes, not guest modules. - JavaScript sync RPC option parsing must accept the V8 bridge's raw boolean mkdir shorthand. In
crates/native-sidecar/src/execution.rs,javascript_sync_rpc_option_bool(..., "recursive")needs to handle both{ recursive: true }and a baretrueargument because guestfs.mkdirSync(path, true)can reach the sidecar as[path, true]; treating that asfalsebreaks recursive host-function writes with spuriousEEXIST. - Loopback TCP tests must use VM-owned listeners unless the port is explicitly exempted. The sidecar blocks outbound guest connections to host-owned
127.0.0.1ports by default, so network tests incrates/sidecar/tests/should listen inside the VM and connect to the guest port instead of opening an unrelated host loopback socket. - Deleting the legacy guest
net.http_requestshortcut must not remove the host-to-guest HTTP server loopback path. Incrates/sidecar/src/execution.rs, guesthttp.request()/https.request()should stay on the guestnet.connect/tls.connecttransport, butvm.fetch()and other host-originated dispatch into guesthttp.createServer()listeners still rely onserialize_http_loopback_request(...),pending_http_requests, and the"http_request"stream event. - Guest
0.0.0.0/::listen and bind requests are VM-local aliases, not host wildcard listeners. Incrates/sidecar/src/execution.rs, unspecified guest TCP/UDP binds normalize onto loopback-owned sockets while preserving the guest-visible unspecified address for listener/socket snapshots, so tests should assert VM-local reachability and query behavior instead of expecting host-visible wildcard listeners or outright rejection. - HTTP/2 loopback listeners need the guest-port mapping and Tokio handoff split correctly. In
crates/sidecar/src/execution.rs, resolve HTTP/2 client loopback connects against the per-process HTTP/2 server table before falling back to generic TCP resolution, and when accepting HTTP/2 server sockets convert the blockingstd::net::TcpStreamintotokio::net::TcpStreaminside the per-session Tokio runtime thread, not in the outer accept loop. - Secure HTTP/2 bridge flows must thread TLS options through the HTTP/2 RPC payloads and keep ALPN pinned to
h2on both sides. Incrates/sidecar/src/execution.rs,net.http2_server_listenandnet.http2_session_connectshould carrytlspayloads into the session launchers, and the TLS defaults needalpn_protocols = ["h2"]or the subsequent h2 handshake can silently fail or downgrade. - TLS-capable TCP sockets must not start a background plaintext reader before the first explicit
net.socket_read. Eager reads on a clonedTcpStreamconsume ClientHello/handshake bytes, which breaksnet.socket_get_tls_client_helloSNI inspection andnet.socket_upgrade_tlson accepted or just-connected sockets. - The sidecar TLS reader and writer share one
rustls::StreamOwnedmutex. Incrates/sidecar/src/execution.rs, timed-out TLS read loops must yield briefly afterWouldBlock/TimedOutso guest request writes can acquire the lock promptly; otherwise undici/fetch HTTPS flows can hit EOF before the request bytes leave the VM. - When splitting
crates/sidecar/src/service.rsinto domain modules, keepservice.rsas the dispatch hub and move domain handlers into sibling-module free functions or impl blocks. Cross-cutting helpers such as JS sync RPC argument parsing and runtime response shims should staypub(crate)inservice.rs, while domain modules (for examplefilesystem.rs) own the handler logic and are invoked through thin delegating stubs so existing tests and dispatch call sites stay stable during mechanical extractions. - Rust permission globs are segment-scoped by default. In kernel/sidecar permission rules, single
*and?match within one path segment and stop at/; use**when a rule needs to authorize nested paths or resources across separators. - Inspection RPC permissions are separate from runtime setup permissions.
FindListener/FindBoundUdprequirenetwork.inspect, andGetProcessSnapshotrequiresprocess.inspect; test fixtures that exercise those handlers still needchild_process.spawnandnetwork.listenallowed so the guest process and listener can start before the inspection request runs. - Host-function registration bootstrap and invocation use different permission paths. In
crates/native-sidecar/src/host_functions.rs, sidecar-ownedregister_host_callbacks(...)work should temporarily swap the bridge policy toPermissionsPolicy::allow_all()while it refreshes/bin/agentos*command stubs, then restore the VM policy; actual guest host-function execution is separately gated byhostFunction.invokeagainst<collection>:<function>resources. - Sidecar request handlers that need rollback must keep fallible mutations inside a
Result-returning closure. In handlers likeregister_host_callbacks(...), a bare block with?returns from the whole request handler before rollback runs; wrap the mutation block in(|| -> Result<_, SidecarError> { ... })()so restore/fail-closed cleanup still executes on errors. - Native-sidecar VM bootstrap must keep a temporary static policy installed. During
create_vmandconfigure_vm, swap inPermissionsPolicy::allow_all()for sidecar-owned/bin/command-path reconciliation instead of clearing the stored policy entirely, or theLocalBridgefallback will deny internal filesystem checks before the guest-visible policy is restored. - Filesystem-side teardown races must fail closed too. In
crates/sidecar/src/filesystem.rs, guest filesystem and Python VFS handlers should treat missing VMs or active processes as stale teardown races: log and return a rejection/Ok(())instead ofexpect(...), because dispose can win after a request is queued but before the response is emitted. - Mapped host paths in
crates/sidecar/src/filesystem.rsmust resolve symlinks against the mapping root before touching the real host. For Python/Pyodide cache and otherAGENT_OS_GUEST_PATH_MAPPINGSaccesses, walk existing path components withsymlink_metadata, reject targets that leave the mapped root, and filterreaddirresults the same way so gueststat/listdircalls cannot leak host metadata through escaped symlinks. - Mapped host-path metadata and symlink ops must not require a pre-existing kernel mirror. In
crates/sidecar/src/filesystem.rs, guest writes underAGENT_OS_GUEST_PATH_MAPPINGSland on the host first, sochmod,utimes,symlink, andreadlinkneed to operate on the mapped host path even when the kernel shadow entry has not been synced yet; only mirror metadata back into the kernel when the guest path already exists there. host_dirmetadata ops must resolve beneath the mount root, reject symlink leaves, and NOT require read on the target (non-root sidecar). Incrates/native-sidecar/src/plugins/host_dir.rs:chown/utimesresolve the parent viasplit_parent,reject_symlink_leaf(anfstatatlstatthrough the anchored parent fd →EPERMon a symlink), then mutate withfchownat/utimensat(.., AT_SYMLINK_NOFOLLOW)against(parent_fd, leaf_name)— no leaf open, so no read requirement, andAT_SYMLINK_NOFOLLOWcloses the check→mutate swap race.stat/existsuseconfine::resolve_parent_beneath+fstatat.chmodis the deliberate exception:fchmodathas noAT_SYMLINK_NOFOLLOW, so it keepsopen_metadata_beneath(leafO_RDONLY | O_NOFOLLOW) +fchmodfor TOCTOU safety, accepting the read requirement. Do NOT reintroduceopenat2, anO_PATHmetadata/leaf anchor,/proc/self/fdre-opens, or a macOS-specific path — the confinement boundary is the single universalconfinemodule (see it andcrates/native-sidecar/CLAUDE.mdfor whyopenat2was removed and why the non-root read constraint drives these choices). AnO_PATHdirectory traversal anchor for search-only intermediate dirs (confine::open_dir_anchor, Linux-only,EACCESfallback) is allowed and is not a metadata anchor.VirtualStatschema changes must cross every filesystem boundary together. When adding stat metadata for mount plugins such ashost_dir, update the RustVirtualStatconstructors (kernel,device_layer, plugin adapters), sidecar filesystem JSON serialization, JS bridge conversions, and the V8Statsshim in the same change or the extra metadata gets truncated before guest code can observe it.- Stateful JS crypto sync RPCs in
crates/sidecar/src/execution.rsare per-process state. Keepservice_javascript_crypto_sync_rpcthreaded with&mut ActiveProcessfor cipher/Diffie-Hellman session handlers, and for AES-GCM treatauthTagLengthas auth-tag output sizing instead of callingCrypter::set_tag_len()during encryption on the current OpenSSL provider. net.pollwaits incrates/sidecar/src/execution.rsmust stay explicitly bounded.service_javascript_net_sync_rpc(...)runs on the sidecar's sync-RPC main thread, so clamp guestwait_msvalues to the 50 ms ceiling inclamp_javascript_net_poll_wait(...); longer waits should return the currently observed socket state after the ceiling expires instead of monopolizing dispose/shutdown or unrelated VM work.- Control-plane stop/continue for shared V8 runtime processes must update kernel state as well as the host runtime PID. In
crates/sidecar/src/execution.rs, whenkill_process_internal(...)handlesSIGSTOP/SIGCONTforuses_shared_v8_runtime()executions, route the signal throughvm.kernel.kill_process(...)after signaling the shared runtime soGetProcessSnapshotand wait semantics reflect the requested stopped/running transition. - Shared-runtime Wasm executions do not have a per-guest host PID to reap. In
crates/sidecar/src/execution.rs,kill_process_internal(...)should terminate embedded Wasm sessions directly forSIGTERM/SIGKILL-style control-plane kills and queue a syntheticActiveExecutionEvent::Exited(...)when the event channel closes without a process-specific host exit notification; waiting on the shared runtime PID will hang because the embedded runtime process stays alive for other sessions. - Nested
child_processshell handling must preserve shell builtins without forcing every command throughsh -c. Incrates/sidecar/src/execution.rs,shell: truerequests still need a real shell for builtins likeexit, but plain commands such ascat /tmp/fileshould stay on the direct resolved-command path or sandbox/host path behavior can diverge again. - Shell grammar (redirects, pipelines, globbing, quoting) belongs to the VM shell. The kernel exposes process, fd, and VFS primitives; the bridge routes shell-mode commands to
/bin/sh -cand never parses shell syntax itself. - Resolve symlinked JavaScript entrypoints before launching the guest Node runtime. In
crates/sidecar/src/execution.rs, follownode_modules/.bin/*symlinks (and existing shell shims) before treating a file as a JavaScript main module, or relative imports likerequire("../src/defaults")resolve against the.binalias instead of the real package bin. - The npm/npx display shim should suppress libnpmexec's synthetic
> npxbanner. Incrates/sidecar/src/execution.rsbuild_host_node_cli_eval(...), the display stub forwardsproc-logoutput directly, so filter the run-script banner emitted for the fakenpxlifecycle event ornpx -y <pkg>no longer matches native stdout. - Process-event handlers must fail closed on stale VM/process state. In
crates/sidecar/src/execution.rsandcrates/sidecar/src/service.rs, any VM/process lookup reached from queued execution events or JS sync-RPC dispatch should log throughlog_stale_process_event(...)and return cleanly instead of usingexpect(...), because teardown can win after an event is queued but before it is drained. - Queued stale-process race regressions should use the process-event channel, not direct handler calls. In
crates/sidecar/tests/service.rs, keep the sequential smoke path that queues envelopes then disposes, and drive real dispose-vs-send races by cloningprocess_event_sender, synchronizing sender/dispose with aBarrier, then draining withpoll_event_blocking(..., Duration::ZERO)and asserting the bridge captured alog_stale_process_event(...)message. - Shared sidecar test helpers should opt into
PermissionsPolicy::allow_all()unless a test is explicitly about permissions. Incrates/sidecar/tests/support/mod.rsand similar harnesses,permissions: Nonenow means default-deny, so generic runtime/filesystem fixtures need explicit allow-all creation to avoid unrelated regressions under scoped Cargo filters likefilesystem. - When extracting large sidecar test modules out of
src/, keep the tests incrates/sidecar/tests/*.rsby wrappinginclude!("../src/...")in a same-named module and nesting the moved assertions undermod tests. This preserves the originaluse super::*access to private helpers, and service-style harnesses also need crate-root re-exports for items that sibling modules import viacrate::{DispatchResult, NativeSidecar, SidecarError}. - If a shared
src/module carries helper code that only those included test harnesses use, gate the helper types/functions and their imports with#[cfg(test)]. That keeps focused library builds likecargo test -p agentos-sidecar --test protocolwarning-free without moving the test scaffold back into production code paths. - Sidecar integration tests surface handler failures as
Rejected(...)responses, not transport-levelErrs. Whendispatch_blocking(...)reaches a real request handler and that handler returnsSidecarError, assert onResponsePayload::Rejected { code, message }; reserveexpect_err(...)for transport or framing failures that prevent a response frame from being produced. - Operator-tunable VM limits live on
VmLimits(crates/sidecar/src/limits.rs), parsed fromCreateVmRequest.metadatalimits.<group>.<field>keys; kernelResourceLimitskeeps itsresource.*keys. Every newMAX_*/*_LIMIT/capacity/retention/sizing constant must be classified incrates/sidecar/tests/fixtures/limits-inventory.json(policywired throughVmLimits, orinvariant/policy-deferredwith a rationale);cargo test -p agentos-sidecar --test limits_auditenforces it.
Testing
- Rust tests live under
tests/, not inline#[cfg(test)] mod testsinsrc/. Move every inline test module in Rust crates to the crate'stests/directory. Exceptions must be justified (e.g., testing a private internal that can't be reached from an integration test). - Some V8-backed Rust integration binaries still trip teardown/init crashes or SIGSEGVs when multiple libtest cases share the same binary. For those targets, keep coverage in one top-level suite test per
crates/*/tests/*.rsfile until the shared-runtime teardown bug is fixed. - Node builtin compatibility regressions should usually land in
crates/sidecar/tests/builtin_conformance.rs: that harness runs the same probe script under host Node and guest V8 and asserts exact JSON parity, which is the fastest way to catch module-shape mismatches likerequire("events"). - Keep
crates/sidecar/tests/builtin_conformance.rsas one top-levelbuiltin_conformance_casestest that forks per-case subprocesses viaAGENT_OS_BUILTIN_CONFORMANCE_CASE; that preserves the exactcargo test -p agentos-sidecar --test builtin_conformanceacceptance surface while isolating V8-backed cases from each other. - For sidecar POSIX conformance coverage, keep
/proc,/dev,waitpid, and process-group assertions as directagentos_kernel/ProcessTabletests where possible, and reserve the sidecar/V8 harness for guest-observable behaviors such as signal delivery that require the full runtime bridge. - Run scoped tests:
cargo test -p agentos-sidecar -- test_name_filterorcargo test -p agentos-sidecar --lib(lib unit tests only, skip integration tests). - Never run bare
cargo test -p agentos-sidecarwithout a filter -- integration tests spawn real processes and can hang. - In
crates/sidecar/tests/service.rs, keep the broad V8-backed integration coverage under a single top-level test because multiple libtest cases in that binary still trip V8 teardown crashes. When a PRD acceptance command needs a filter token likejavascript_network_dns, preserve that token in the single suite test name instead of adding another top-level wrapper. - In
crates/sidecar/tests/service.rs, permission tests that only need a parent JavaScript process for child-process bookkeeping should seed anActiveProcesswithkernel.create_virtual_process(...)instead ofstart_fake_javascript_process(...); this exercises the sidecar path without coupling the scoped suite to V8 teardown state. - Split
execution/tests/javascript.rs(46 tests) intojavascript/{builtin_interception,module_resolution,env_hardening,sync_rpc}.rs. - Do not hide first-party Rust coverage behind
#[ignore]; if an integration test is too expensive or flaky for the default suite, split or scope it so the active acceptance command can still run it honestly.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

