# Decisions Why Sausage is the way it is. `PROTOCOL.md` and the code own the details. When this file disagrees with them, they win. ## The shape - **JSON-RPC, not component interfaces.** Every language can read and write lines of JSON, and models know JSON-RPC from LSP and MCP. A call has a result, like an LLM tool call. - **A process per call.** WASI has no threads, so processes give parallelism. A new version applies at the next call, and old processes retire after a grace period. - **Attached by default.** A process does not outlive its caller by accident. A long-running process must ask for `detach`. - **Services in one file.** Only the core starts and restarts them, so upgrades and singletons need no logic in plugins. - **Files to inspect, calls to act.** This keeps the core API small, and the agent's file tools are enough to explore the world. - **The core accepts only `.wasm` files.** It knows no source language. `cargo` is one way to get a `.wasm` file. - **The world folder is the source of truth.** Copy a plugin folder into another world, and it works there. - **The agent is a normal plugin.** It can read and upgrade its own source, and change how it does inference. ## Interfaces - **Generated imports and interface checks, without version numbers.** A model that translates a description by hand makes errors. A generator does not. The check catches the most common error in a world that changes itself: a change to one plugin breaks another one. - **A small schema subset.** With Draft 7 and a fixed subset, our own check can decide every case. It never has to guess. - **Docs are part of the interface.** Other agents work from them, so the SDK requires a doc comment on each method, type, and field. - **The check covers calls, not state.** Old and new versions share `/state`. A plugin keeps its state format compatible, or migrates it in `rpc.retired`. ## Minimal on purpose The core does only what a plugin cannot do for itself. Everything else can be a plugin, or a change that the agent makes to itself. - **No permissions, no limits, no hiding.** Any process can call, upgrade, or stop any plugin, read and write every file, and use the network. The checks protect against mistakes, not against plugins. Locks are advisory. - **Locks are in the core.** A plugin cannot see that another process died, so it cannot release that process's lock. The core can. - **Our own VFS, in its own crate.** It works on Linux and macOS, it makes `/proc` live, and plugin-served files need it later. Mounts now, overlays later. - **TCP endpoints for now.** They need no host code. VFS pipes can replace them later behind the same SDK API. - **Simple scheduling for now.** An epoch tick every 10 milliseconds keeps the core responsive and makes kills reliable. - **The agent is dumb.** It has a short prompt, a few tools, an append-only history that it sends in full, and no compaction. When the context is too large, it stops sending the oldest turns, so it never gets stuck. ## Small choices - **Plain POSIX files.** Programs like `tempfile`, git, and SQLite expect normal files. Atomic writes use a temporary file and `rename`. - **Tests run under WASI.** `cargo test` on the host cannot find failures that occur only in WASI, for example a missing WASI function or a panic at start. The test runner uses the same Wasmtime and the same mounts as the core. - **The SDK is not published.** `cargo` points `sausage-plugin = "0.1"` at its own copy, which it also shows in `/plugins/cargo/sdk/`.