# Sausage You can see how the sausage is made. Sausage is a world of small WASI programs ("plugins") that you grow by talking to it. A plugin is a `.wasm` file with JSON-RPC methods. Each call to a plugin starts a new process. The agent is a plugin too: it writes new plugins in Rust, builds them, tests them, activates them, and can change its own code. ## Start You need [Nix](https://nixos.org/download) with flakes, and an LLM: the OpenAI Responses API, an OpenAI-compatible Chat Completions API (OpenRouter, Ollama, and most other providers), or the Anthropic Messages API. No clone needed: ```sh nix run git+https://gitea.surma.technology/surma/sausage ``` This creates a world in `./world` the first time (it builds the agent: the first build on a machine takes a few minutes, later worlds reuse the compiled crates), then starts it with a console. Later runs start the existing world. The two steps on their own: ```sh nix run git+https://gitea.surma.technology/surma/sausage -- init # creates ./world and builds the agent nix run git+https://gitea.surma.technology/surma/sausage -- run # starts the world and a console ``` `init` asks nothing. It writes `world/config/agent.yaml`, with a comment for each field and an example for each API. Edit it before the first chat: choose the API, the base URL, the model, the key, and the thinking level. Until then, a chat answers with an error that names the missing field. Both commands take another folder as an argument, for example `... -- run my-world`. Compiled code is cached outside the world, in `$XDG_CACHE_HOME/sausage/` (`~/.cache/sausage/` without the variable). All worlds share it. `--cache-dir ` changes it for `init` and `run`. To keep a world on the newest version, run it in a loop: ```sh nix run git+https://gitea.surma.technology/surma/sausage#loop # ./world, created if needed nix run git+https://gitea.surma.technology/surma/sausage#loop -- my-world # an existing world ``` When the host crashes or a plugin calls `core.restart`, the loop fetches the newest commit and starts it again. The loop sets `SAUSAGE_LOOP=1` to enable that RPC; without it, restart returns an error and leaves the host running. Restart answers first, then cleanly stops all processes and exits with code 75. `quit` (code 0) ends the loop. Set `SAUSAGE_FLAKE` to run another flake URL instead, for example your fork. **The mediator and all agents NEVER call `core.restart` without the person's explicit approval each time.** This also applies to legacy `core.exit`, an alias with the same supervisor gate, response-before-exit behavior, and request coalescing. See [the protocol](PROTOCOL.md#host-restart) for the shutdown contract. From a clone (`git clone https://gitea.surma.technology/surma/sausage`), the same commands are `nix run`, `nix run -- init`, `nix run -- run`, and `nix run .#loop`. ### Headless `--headless` (or `SAUSAGE_HEADLESS=1`) turns the console input off. The host runs until SIGTERM or SIGINT (exit code 0) or until a plugin calls `core.restart` (requires `SAUSAGE_LOOP=1`; exit code 75 restarts the loop): ```sh nix run git+https://gitea.surma.technology/surma/sausage#loop -- --headless my-world ``` ## The console | Input | Effect | | --- | --- | | text | a message to the agent (`agent.chat`) | | `. {json}` | a call. The console prints the result. | | `ls [path]`, `cat ` | the filesystem as a process sees it, with `/proc` and `/run` | | `methods ` | the methods of a plugin, with params and docs | | `ps` | the running processes | | `log [plugin or pid] [-n N]` | the journal | | `activate `, `revert ` | activate a new version, or go back | | `stop `, `kill ` | stop a process | | `help`, `quit` | | ## The world folder ```text plugins//plugin.wasm the current version of a plugin plugins//source/ its source state// the state of a plugin, by convention state/core/journal.sqlite the journal: stderr of all processes, and core events config/boot.yaml the services that start with the world config/agent.yaml the configuration of the agent ``` Rust builds use the SDK in `plugins/cargo/sdk/` directly. The host seeds this folder only when it is missing; restarts and host upgrades preserve existing files. SDK edits take effect on the next `cargo.build`, without a restart. To reset to the host's bundled SDK, back up any edits and remove the whole folder; the next startup or build re-seeds it. Each process also sees `/proc` (the processes and the state of the core), `/self` (its own folder in `/proc`), and `/run` (shared files in memory). To replace a plugin by hand, copy a `.wasm` file to its `plugin.wasm`. That skips the interface checks. `revert ` goes back to the version before the last activation. ## More - [PROTOCOL.md](PROTOCOL.md): calls, processes, the filesystem, locks, interfaces, and `cargo`. Read this to write a plugin in any language. - [DECISIONS.md](DECISIONS.md): why Sausage is the way it is. - [`sdk/`](sdk/): `sausage-plugin`, the SDK for Rust plugins. - [`examples/`](examples/): small plugins. - [AGENTS.md](AGENTS.md): how to work on Sausage itself.