# Run Sausage v3 on Citadel Use the bootstrap web chat for conversations. Credential approvals remain on separate host pages. **TL;DR:** Start a separate v3 world, create the SSH tunnel below, and open http://localhost:8080. The Nix package supplies the userland bundle, source tree, and enabled chat service. Keep the complete world folder between starts. ## Build and start Run host commands from a checkout of the `v3` branch on Citadel. Use Nix with flakes. The package supplies the native Rust builder and its tools. The package entry point is: ```sh nix run . -- run "$HOME/sausage-v3" /.sausage/agents/`. The models extension reads these files at each run boundary. Edits affect the next run without a restart. An explicit model override can take precedence over a family. The initial console root has a host-defined model. Do not assume a family edit changes every existing conversation. All real model requests retain the host proxy transport. Sources: [`credentials.rs`](../host/src/harness/credentials.rs), [`main.ts`](../host/js/main.ts), and [`models`](../extensions/models/README.md). ## Change extensions The world checkout is `/src/sausage`. The loader follows its **`main`** branch, not the host checkout's `v3` branch. Each extension lives at `extensions/NAME/server.ts` inside that checkout. Commit extension edits to `main` with world git. A saved, uncommitted edit does not reload an extension. Use `--no-gpg-sign` for commits. The loader imports a detached snapshot under `/run/sausage/extensions/COMMIT`. It validates the entire candidate before it replaces the live registry. A broken candidate leaves the previous good commit active. An active tool call retains its implementation. The next call uses the new implementation. Read `/proc/extensions` through the agent's file tools to inspect `current`, `good`, and `error`. To restore the last good branch ref, ask the agent to execute: ```sh extensions-revert ``` The command preserves editable files. It changes `refs/heads/main`, which triggers the normal reload. At startup, the loader tries the tip and then the last good commit before it resumes work. Source: [`extensions`](../extensions/README.md) and [`extensions.ts`](../host/js/extensions.ts). ## Everyday tools inside the world These are world programs, not console commands. Ask the agent to run them. | Tool | Use and limits | | --- | --- | | `cargo` | Build, run, and test Rust programs. The host copies the workspace through the VFS, fetches dependencies, then builds offline in namespaces. It publishes WASI artifacts into the world. Other targets are unsupported. | | `box` | Build non-Rust projects or run browser tests in disposable containers. The default service is `citadel.vpn.surma.technology:8093`. It requires network access and service availability. Remove boxes after use. | | `undo` | Inspect tags and restore filesystem changes. Later edits can conflict. Network effects and native builds are not reversible. Retention is seven days or 4 GiB of unique content. | | `systemctl` | Control world init services, not Citadel's systemd. Persistent units live under `/etc/systemd/system`. Init observes edits without daemon reload. | | `journalctl` | Read world service logs under `/var/log/journal`. Each unit retains a 1 MiB log and one rotated file. | | `git` | Manage world repositories. HTTPS credential rules can inject authorization through the host HTTP hook. SSH remotes use host signing. | | `ssh` | Execute a remote command without a PTY. Public identities and signatures come from the host. Private keys never enter the world. Host keys live in the world's known_hosts file. | Init starts when the host starts the runtime, if `/bin/init.wasm` exists. Transient units under `/run/systemd/transient` disappear after restart. A missing credential grant causes a pending host request, not an automatic approval. A changed SSH host key fails even with the accept-new policy. Command reference and implementation evidence: [`builder`](../host/src/builder/README.md), [`box`](../userland/box/README.md), [`undo`](../userland/undo/README.md), [`init`](../userland/init/README.md), [`git`](../userland/git/README.md), and [`ssh`](../userland/ssh/README.md). ## Build a world UI with the host API World programs call **`http://host.sausage`** through standard WASI HTTP. The listener on port 8090 does **not** expose harness routes. The seeded chat server forwards `/api/...` to `/harness/...` through WASI HTTP. The bootstrap page polls `entries?after=` once per second rather than using a persistent stream. Keep credential approval and secret entry on host pages. | Method and route | Result or request | | --- | --- | | `GET /harness/conversations` | Conversation records, titles, ownership, ancestry, and state. | | `GET /harness/conversations/ID/entries?after=0` | `{entries:[...]}` in ascending order. | | `GET /harness/conversations/ID/stream?after=0` | NDJSON entries, replay first, then live commits. | | `POST /harness/conversations/ID/submit` | `{content:"text",requestId:"stable-id"}` returns 202 and a submission ID. Reuse the request ID for retries. | | `POST /harness/conversations/ID/stop` | Stops active turns and owned work. Queued input remains. | | `GET /harness/events?after=0` | NDJSON events, replay first, then live commits. | | `POST /harness/extensions/NAME/actions/ACTION` | `{args:{...},conversationId?:number}` invokes an exported user action. | | `GET /harness/models` | Public model catalog without authentication data. | | `GET /harness/families` | World model families. | | `GET /harness/extensions` | Loaded extension status. | | `GET /harness/credential-requests` | Pending conversation requests with host approval links. | The `after` cursor is exclusive. Reconnect with the last record ID. Streams close when the client disconnects or the harness stops. Do not render a stream as one JSON response. An unavailable harness returns 503. Invalid input returns 400. Missing resources return 404. Source: [`host API contract`](../host/src/api/README.md), [`harness-api.ts`](../host/js/harness-api.ts), and [`harness/http.rs`](../host/src/harness/http.rs). ## Known gaps before cutover - Laptop access, passkey ceremonies, secret entry, and browser approval remain **to check with Surma**. - Startup checks use fake proxy credentials. They do not verify a real model session or external credential injection. - A usable `llm-proxy` credential is mandatory even before the first chat. - The bootstrap chat is deliberately plain. There is no item editor or credential dashboard. - The console has no shell commands, transcript navigation, or special quit command. - `sausage sh` requires `-c`. Its interactive shell is not implemented. - This guide does not migrate a v2 world. Keep the live v2 folder untouched. A successful local start does not verify external services or the production passkey origin.