Make legacy core.exit share core.restart's supervisor gate and pending
request. Seed the stable agent prompt and boot comments with the approval
and shutdown contract, and check real init output under a deadline.
Cover both aliases' gate, response grace, coalescing and exit status.
Card: SAU-135
Return success before scheduling the existing shutdown path, coalesce pending
requests, and mark #loop invocations with SAUSAGE_LOOP=1. Keep core.exit
compatibility and document explicit per-call approval for all agents.
Card: SAU-134
- thinking (off, low, medium, high, xhigh, max) is an enum: serde rejects
unknown levels in the config, and the schema of agent.chat lists them.
reasoning_effort, a second name for the same setting, is gone.
- agent.chat takes an optional thinking level for one turn.
- off really switches thinking off: OpenAI gets the effort none, and
Anthropic gets disabled thinking (newer Claude models think by
default). A model that cannot switch thinking off gets low.
- Unset means the model's default. Anthropic thinking blocks now return
unless thinking is off, because newer models think by default.
- The template sets thinking: medium and shows it in each example, with
current model names.
- Checked against the proxy with gpt-6-luna, glm-5.3-flash, and
claude-haiku-5-5.
- /config/agent.yaml and /config/boot.yaml replace the JSON files, read
with serde_yaml_ng (also in the agent, inside WASM).
- sausage init asks nothing and reads no SAUSAGE_* variables. It writes
commented templates with an example for each API, and prints the path
to edit. Until the agent is configured, agent.chat names the missing
field. allow_no_token: true permits a local model without a key.
- The agent speaks openai-chat-completions, the format of OpenRouter,
Ollama, and most providers. base_url follows each SDK: with /v1 for
the OpenAI shapes, without it for Anthropic.
- Checked against the proxy with glm-5.3-flash: the agent wrote, built,
and activated a counter plugin in 55 s.
- The cargo target folder is <cache>/cargo-target, next to Wasmtime's
cache, which moves to <cache>/wasmtime: Wasmtime's cleanup worker
deletes unknown entries in its folder, also Cargo's artifacts.
- Builds use the SDK at <cache>/sdk/<content hash>/, so cargo reuses
the compiled SDK in every world. /plugins/cargo/sdk/ stays for agents.
- Tests run in the release profile and share compiled crates with the
release build.
- The cargo and cli tests use a persistent cache in CARGO_TARGET_TMPDIR:
warm, the cargo suite takes 11 s (was 235 s) and the cli suite 6 s
(was 149 s).
- nix flake check runs ignored stress tests. AGENTS.md: rules for fast
tests.
The host watches the whole world folder recursively with the notify crate
(any writer counts, .sausage-tmp-* skipped, ~100 ms coalescing per path).
A new or changed actor/<id>/actor.wasm (or new folder actor/<id>) is
booted as at start once quiet: new = spawn (tested first), changed =
upgrade. The broker `scan` request is gone; the boot pass stays, plus a
full pass when the OS watcher overflows.
New broker requests watch/unwatch {path} (saved in actor.json `watches`)
deliver fs_changed {path, op: write|create|remove|rename, to?} from `fs`,
not routed, dropped when the mailbox is full; overflow sends every watcher
one fs_changed {path:"/actor", op:"rescan"}.
Card #91 (multi-host step 1).
- 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).
So `nix run git+https://gitea.surma.technology/surma/sausage` works.
- flake: .#loop without a folder runs bare sausage.
- README: mention the bare command and the bare loop.
- broker: `{"type":"exit"}` answers `exiting`; `sausage run` then stops all
actors and exits with code 75.
- flake: apps `loop` / `loop-internal` run `nix run --refresh git+ssh://.../surma/sausage -- run <world>`
in a loop; exit code 0 (/quit) ends the loop, anything else restarts.
- PROTOCOL.md, README.md, test in cli/tests/host.rs.
Not compiled: written by the Sausage agent, which cannot build the native host.
Host:
- test first: a new version is tested where it lies; only an installed
version goes to versions/, and instances run from there
- data/ and public/ are shared by all versions; no snapshots; rollback
restores code only
- no re-delivery, status.json, list, remove/archive, smoke test, data/
hiding, or stdin timeout; rollback needs a version
- supervisor.rs split out; one place for installing a version
- init only writes the agent folder; run installs it like any actor
- console: @actor, text to the agent, /help, /quit
Agent:
- every text goes out as a broadcast; 5-line prompt; 5 tools that describe
themselves; turn.json only marks an active turn
Docs: PROTOCOL.md, README.md, DECISIONS.md, AGENTS.md rewritten.
Examples: only notes and notes-v2.
Imported from the spike branch, with:
- a library crate (Host API) for the CLI and the tests
- JSON test scenarios for candidates
- commit on close only for new or truncated files
- a Nix flake: nix run -- init, nix run -- run