# Working on Sausage (v3) Sausage is a world of WASI programs and durable agents. It is meant to be read and changed by agents, including its own. Keep it that way. This branch (`v3`) rebuilds Sausage. The plan and its decisions (D1, D2, …) are in `~/research/sausage-v3/PLAN.md`. `README.md` describes the current build and layout. ## The boundary - **The world is the sandbox.** Everything inside the world sees and changes the whole world. Do not add inner boundaries, permissions or per-agent views. The VFS is a safety net against mistakes, not a wall against attackers. - **Host calls pierce the sandbox.** The only host import beyond standard WASI is the process interface (spawn, wait, kill). Do not add another one. Everything else uses standard WASI 0.2 interfaces: files through the VFS, `wasi:http` (the host API on its reserved host name, credential injection, signing), and `wasi:sockets`. - **The credentials manager in the host is the one real security boundary.** Its managed secrets never enter the world. Approvals need a passkey. The one exception is the LLM proxy key in `/etc/sausage/config.yaml`. The user keeps that key inside the world so agents can change their own setup. - **Native code is the exception.** The only native work for the world is the Rust builder, and it runs in user, mount and network namespaces. ## Priorities 1. **Correct.** Every behavior has a test. 2. **Simple and short.** Prefer the obvious code. No abstraction for one caller. No configuration that nobody asked for. 3. **Readable.** A new reader must understand a file without the others. Each module starts with a doc comment that says what it owns. 4. **Efficient** on the paths that run per command and per model turn. ## Layout - `host/`: the host crate (package and binary `sausage`): the world, the process table, the harness. `host/src/exec.rs` is the contract between the harness and the process table. - `vfs/`: `sausage-vfs`, the virtual filesystem for WASI guests and for host code. It knows nothing about Sausage. Host code reads and writes the world only through it. - `userland/`: the default CLIs of a world, built for `wasm32-wasip2` in the root Cargo workspace. The patched Brush crates live in `userland/brush/source/` and share the root lock file. - `spikes/`: accepted prototypes. Read them for evidence, copy from them, do not build on them. ## Programs in the world - Agents write CLIs and servers. That they are WASI binaries is a detail, not a concept to explain. - The platform is WASI 0.2 components. Rust programs build for `wasm32-wasip2`. WASI 0.1 programs run through an adapter. ## Checks ```sh nix develop -c cargo test -p sausage -p sausage-vfs nix develop -c cargo clippy -p sausage -p sausage-vfs --all-targets -- -D warnings nix develop -c nu userland/bundle.nu # For one tool, select its package and WASI target explicitly: nix develop -c cargo build -p git --target wasm32-wasip2 --release ``` `nix flake check` checks the packaged host, its bundle, and sandbox-compatible tests. ## Tests Host integration tests share one executable: ```sh cargo test -p sausage --test it cargo test -p sausage --test it -- chain:: ``` Use the required Nix environment and build slot wrapper for these commands. Add test modules under `host/tests/it/` and declare them in `it/main.rs`. Use fully qualified child test filters with `--exact`. See `host/tests/README.md` for fixture and isolation details. Tests must stay fast: - Only a few tests may wait for a timing (grace periods, deadlines). - Poll for a condition with a deadline. Do not sleep. - Do not test unrealistic load, such as many fast cycles. - `#[ignore]` only disables a test for a short time, with the reason in the attribute. - Tests that build or compile guests use a persistent cache (for example under `env!("CARGO_TARGET_TMPDIR")`), so a warm run does not compile again.