The privacy claim is not a policy promise — it is inspectable in the code and observable on the network. With http_request removed, the only ways anything leaves your machine are a web search query, a page fetch, and the MCP servers you configured. Each of those exits is recorded.
::egress ledger and air gap
Every network exit — host, bytes, channel — is recorded and renders live in the rail (⇅ sent → host · bytes · channel). /privacy shows what can leave, /privacy egress what did, and /privacy airgap on seals the boundary: web tools refuse, remote MCP calls refuse, and every blocked attempt shows in the ledger as ⛔ air-gap blocked. A fully local turn's receipt reads local-only; silence means nothing left.
/privacy what CAN leave this machine
/privacy egress [clear|n] the per-event ledger of what DID
/privacy airgap [on|off] [--save]The test suite carries a no-new-egress grep guard over the source tree, so a new network path cannot land unnoticed.
::prompt-injection quarantine
Web pages, remote MCP results, and the ingested corpus are untrusted input. Content that tries to steer the agent ("ignore your previous instructions", tool coercion, role overrides) is detected, visibly flagged in the trace, and fenced between data-not-instructions markers before the model sees it. In the default gate mode, the first tool batch after a flagged observation faces the approval gate regardless of risk tier — one fresh human look at calls whose arguments may derive from injected content. Tool classifications come from the live registry (tools declare untrusted=True), so the coercion scan covers every gated tool, MCP tools included. @file attachments and piped stdin warn when instruction-shaped, but never block.
runtime.quarantine: off
no scanning
warn
scan, fence, and show flags — never change gating
gate (default)
warn, plus the first tool batch after a hit faces the gate
::the trust receipt
The one-line stats receipt under each answer carries a trust segment: local-only, or the turn's egress summary (⇅ N sends · bytes → host) in yellow, blocked attempts, and how many calls faced the approval gate. /trace answer expands it into full answer provenance — each cited source's origin and trust flags, what left the machine, and the human gate decisions.
::secrets
- –At the gate — each gated call's arguments are scanned for keys, tokens, and private-key blocks; a hit warns inline.
- –In shell children —
run_shellchildren do not inherit secret-shaped environment variables (*API_KEY*,*SECRET*,*TOKEN*,*PASSWORD*,*CREDENTIAL*,ANTHROPIC*,OPENAI*,AWS_*,GITHUB_*by default). The fragment list isshell.env_scrub. - –At the network boundary — outgoing MCP arguments and any remote-Ollama send are subject to
runtime.redaction(off/warn/redact); local Ollama calls are never scanned because there is no boundary. - –Nowhere else — no Saturn feature takes an API key. MCP secrets are plain env vars expanded from
.env.
::trust settings are session-only unless saved
runtime.auto_approve, runtime.airgap, runtime.quarantine, runtime.redaction, runtime.grant_scope, and shell.env_scrub set through /config, /policy, or /privacy apply for the session only unless you pass an explicit --save. A loosened security posture is never written to disk silently.
::what the benchmark measures
python benchmark.py runs the graded trust benchmark — the numbers the product's claims rest on: the grounding judge's catch rate, approval-gate coverage (every non-read-only call must have faced the gate), the injection flag rate (a planted corpus document carrying instruction-shaped content, retrieved through the live knowledge-base path), and the semantic write gate's fabrication catch rate. --strict exits 1 on any graded FAIL. Reports land in logging/benchmarks/.