Files
sausage/README.md
T
Sausage agent 8a533f0158
ci / check (push) Successful in 14m24s
Run without a clone: bare sausage creates ./world if needed and runs it
- cli: the subcommand is optional; without one, sausage runs ./world and
  runs init first when ./world is not a world yet (test: cli/tests/cli.rs).
- flake: .#loop without a folder runs bare sausage.
- README: nix run git+https://gitea.surma.technology/surma/sausage(#loop),
  clone only for working on Sausage.
2026-10-16 20:56:59 +00:00

3.3 KiB

Sausage

You can see how the sausage is made.

Sausage is a world of small programs ("actors") that you grow by talking to it. Each actor is a WASI program with stdin and stdout. Actors send each other JSON messages, one per line, through a broker. The agent is an actor too: it writes new actors in Rust, builds them, tests them, starts them, and can change its own code.

Start

You need Nix with flakes, and an API token for an LLM (OpenAI Responses or Anthropic Messages API). No clone needed:

nix run git+https://gitea.surma.technology/surma/sausage

This creates a world in ./world the first time (it builds the agent, which takes a few minutes) and then starts it with a console. Later runs start the existing world. The two steps also exist on their own:

nix run git+https://gitea.surma.technology/surma/sausage -- init   # create ./world
nix run git+https://gitea.surma.technology/surma/sausage -- run    # start it

init asks for the API shape (openai-responses or anthropic-messages), the base URL, the model, and the token. It reads SAUSAGE_API, SAUSAGE_BASE_URL, SAUSAGE_MODEL, and SAUSAGE_API_TOKEN first. The values go to world/actor/agent/data/config.json. init and run take another folder as an argument, for example -- run my-world.

To keep a world on the newest version, run it in a loop:

nix run git+https://gitea.surma.technology/surma/sausage#loop             # ./world
nix run git+https://gitea.surma.technology/surma/sausage#loop -- my-world # an existing world

The loop runs the newest sausage from that URL (nix run --refresh). When the host crashes or an actor sends @broker {"type":"exit"}, the loop fetches the newest commit and starts it again. /quit ends the loop. Set SAUSAGE_FLAKE to run another flake URL instead, for example your fork.

To work on Sausage itself, clone it (git clone https://gitea.surma.technology/surma/sausage) and use nix run, nix run .#loop and nix develop in the checkout.

In the console:

write an actor "notes" that stores notes, and start it   → text to the agent
@notes {"type":"add","text":"milk"}                      → a JSON message to an actor
@agent hello                                             → text to an actor
/quit

The world folder

The folder is the source of truth. Every actor lives in world/actor/<id>/:

actor.wasm     the current version
actor.json     installed version, running, subscriptions
source/        the source of the current version
public/        files that the actor publishes
data/          the actor's state
stderr.log     what the actor and the broker write about it
versions/<n>/  every installed version: actor.wasm, source/, meta.json

To add or replace an actor by hand, put an actor.wasm (and its source/, with the tests in source/tests/) into its folder. Then restart the world or send @broker {"type":"scan"}. The broker tests the file before it uses it. If the tests fail, the old version keeps running, and stderr.log says why.

More

  • PROTOCOL.md: messages, the filesystem, the broker, cargo. Read this to write an actor in any language.
  • sdk/: sausage-actor, the SDK for Rust actors.
  • examples/notes: a small actor with a test.
  • AGENTS.md: how to work on Sausage itself.