Files
sausage/DECISIONS.md
T
surma bcde6ba325 Plain POSIX files: remove commit on close (fs.rs)
Staging every write until close broke tempfile, git, and SQLite, which
expect normal files. Actors that need an atomic publish write a temporary
file and rename it; the SDK has write_atomic for that.
2026-10-15 23:33:20 +01:00

2.8 KiB

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

  • Actors are WASI commands, not components with interfaces. stdin, stdout, files, HTTP, and sockets are enough, and every language can do them.
  • Messages are JSON lines through a broker, fire and forget. Like Erlang: no acknowledgments, no request/response. A reply is a message with reply_to. Sausage is not a reliable message bus.
  • The broker accepts only .wasm files. It knows no source language. cargo is one compiler actor; others can add more languages.
  • The world folder is the source of truth. Everything about an actor is in actor/<id>/. Copy a folder into another world, and it runs there.
  • The agent is a normal WASM actor. It can read and upgrade its own source, and change how it does inference.

Minimal on purpose

The harness does only what it needs to keep going. Everything else can be an actor, or a change that the agent makes to itself.

  • The host is not self-modifiable; actors are. So the host keeps only what an actor cannot do for itself: routing, running instances, versions, tests before an install, and the rollback of a version that crash-loops. Without that rollback, a broken self-upgrade would end the agent.
  • No permissions, no limits, no hiding. Any actor can message, upgrade, or stop any actor, read every folder, and use the network. People who want rules can build them.
  • No re-delivery and no state snapshots. A crash loses the message, and all versions of an actor share data/ and public/. A rollback restores code, not data.
  • 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. An earlier version staged every write until close. That broke tempfile, git, and SQLite, which expect normal files. Atomic publishing is the usual temporary file + rename.
  • Test first, then switch. A new version is tested where it lies. Only a version that passes goes to versions/, and the old one runs until then. versions/ keeps every version that was installed, so a rollback can always go back. A file that fails stays where it was put.
  • Tests are JSON transcripts next to the source. They run on a copy of the actor's state, without network, so a test cannot send real requests.
  • broker and cargo never answer a reply, so no two actors answer each other forever. The agent starts a turn only for text that is not a reply, for the same reason.
  • The SDK is not published. cargo points sausage-actor = "0.1" at its own copy, which it also shows in /actor/cargo/public/sdk/.