$local_first=truecloud_calls=0telemetry=off

ai agents shouldshow their work.

Saturn is a terminal agent for the admin of your life: your files, notes, calendar, mail, and messages. It runs on your hardware, every tool call is written to the screen as it happens, and when it wants to change or send something, it asks first.

$ curl -fsSL saturdayai.org/install.sh | sh

01::a real run

watch it work.

» how much did I spend on groceries in september? it's all in groceries.csv

✓ agent 7.3s iter 1 · 7.4k ctx · 12 tok/s → read_file
└─ read_file(file_path='groceries.csv')
└ date,store,amount 2026-09-02,trader joe's,48.17 2026-09-06,farmers market,22.50 2026-09-11,whole…
✓ agent 7.0s iter 2 · 7.6k ctx · 13 tok/s → calculate
└─ calculate(expression='48.17 + 22.50 + 71.36 + 39.82 + 112.40 + 18.75')
└ 313
✓ agent 10.5s iter 3 · 7.7k ctx · 12 tok/s → answer

You spent $313.00 on groceries in September — 6 trips:

 

- Sep 2 — Trader Joe's — $48.17

- Sep 6 — Farmers market — $22.50

- Sep 11 — Whole Foods — $71.36

- Sep 15 — Trader Joe's — $39.82

- Sep 21 — Costco — $112.40

- Sep 27 — Farmers market — $18.75

 

Sources:

[1] read_file(file_path='groceries.csv')

[2] calculate(expression='48.17 + 22.50 + 71.36 + 39.82 + 112.40 + 18.75')

ctx 7.7k · 11.9 tok/s · 24.8s total · run #2 · qwen3.8:27b · saturn v2

fig. 01 — run #2, qwen3.8:27b, 2026-10-03. rendered from the run's export record, unedited. 3 model passes: read the file, add it up, answer.

one loop

each pass calls tools or answers. a chat question is one pass and one model call; a lookup is two passes, and a pass that calls a tool thinks it through first.

every call on screen

each tool call prints with its arguments and what came back, as it runs.

sourced answers

the answer ends with the exact calls behind it, and arithmetic is computed, never guessed.

your move

the prompt returns to you. side effects wait at the gate — see 02.

02::the gate

it asks first.

» save a two-line summary of groceries.csv to notes.md

✓ agent 7.3s iter 1 · 7.4k ctx · 12 tok/s → read_file
└─ read_file(file_path='groceries.csv')
└ date,store,amount 2026-09-02,trader joe's,48.17 2026-09-06,farmers market,22.50 2026-09-11,whole…
✓ agent 7.0s iter 2 · 7.6k ctx · 13 tok/s → calculate
└─ calculate(expression='48.17 + 22.50 + 71.36 + 39.82 + 112.40 + 18.75')
└ 313
✓ agent 12.5s iter 3 · 7.6k ctx · 10 tok/s → write_file
■ gate write_file — denied
✓ agent 13.6s iter 4 · 7.8k ctx · 10 tok/s → answer

I didn't write to notes.md — that action was declined.

 

For reference, the two-line summary I was about to save:

 

Groceries (Sept 2026): 6 trips totaling $313.00, from $18.75 (farmers market) to $112.40 (Costco).

Most frequent stores: Trader Joe's (2 trips) and farmers market (2 trips); biggest single spend was Costco at $112.40.

 

Want me to adjust the wording, or save it somewhere else?

 

Note — the following could not be completed:

- write_file(file_path='notes.md', content="Groceries (Sept 2026): 6 trips totaling $313.00, from $18.…) — declined at the approval gate — not done

 

Sources:

[1] read_file(file_path='groceries.csv')

[2] calculate(expression='48.17 + 22.50 + 71.36 + 39.82 + 112.40 + 18.75')

gates prompted 1 · approved 0 · run #6 · qwen3.8:27b

fig. 02 — run #6, qwen3.8:27b, 2026-10-03. the gate denied write_file; notes.md was never written. headless runs deny by default.

Every call that changes or sends something stops at the gate with the real artifact on screen: the diff, the full command, the number and the exact text of a message. Enter rejects, and an always-allow answer lasts for the turn, not forever. A text message asks every time — no setting skips it. Headless runs deny by default; --yolo opens the gate, and that choice is on the record too.

03::the policy file

policy,not promises.

# saturn.policy

6 rules · read-only

local_first = true

Models, context, and data stay on your machine. No API key anywhere, no telemetry. What can leave is a short list: a search query, a page fetch, a message you approved, and the MCP servers you configured.

show_work = always

Every model pass and tool call is written to the screen as it happens — not summarized after the fact — and every run replays offline from its export record.

side_effects = gated

Approval gates sit in front of every write, command, send, and remote call, showing the real diff, the full command, or the recipient and the exact text. Enter rejects. Grants expire with the turn.

answers = traced

Every answer that used a tool ends with the exact calls and documents behind it. What failed or was declined is listed under the answer, never papered over.

egress = recorded

Every byte that leaves is logged by host and channel and printed under the answer. Air-gap the whole thing with one command; web pages, mail, and files are quarantined against injection.

trust_settings = explicit

A loosened posture — an open gate, a lifted air gap, a relaxed tier — is session-only unless you say --save. Nothing weaker is ever written to disk silently.

04::capabilities

what it does.

llm

qwen3.5:9b · loaded · cloud 0

local models, sized to your mac

Open models through Ollama on your own hardware. /models reads your chip, its memory, and its bandwidth, then recommends the largest model that fits and still runs at a usable speed. No API key anywhere in the product.

mac

create_reminder · tomorrow 9:00 → your phone

your mac, through its own apps

Notes, Calendar, Mail, Contacts, Reminders, Messages, and Shortcuts, plus the page in your browser and the files selected in Finder. Everything goes through the app itself, so what Saturn does shows up where you'd look. Mail is drafted, never sent, and /tools off turns off any app you don't want it near.

loop

✓ read_file · ✓ calculate · ▸ answer

pause, steer & think

One loop, every pass on screen. Press Esc to pause a running turn: continue, type a correction to steer it, or abort. On a multi-step errand the agent keeps a checklist you can watch in the rail. Saturn thinks before it calls a tool and never before a plain answer; the status bar times each thought, Esc stops it, and /think sets fast, auto, or deep.

gates

send_message → always asks · y / N

tool approval gates

Every write, command, and send stops with the real diff, the full command, or the recipient and exact text on screen. Enter rejects. A text message asks every time, and a number the model made up is refused before you're asked.

answers

[1] read_file · [2] calculate · 0 failed

answers you can check

An answer that used tools ends with the exact calls and documents behind it, and /trace source shows the full material. Failed and declined calls are listed under the answer. Arithmetic and dates are computed, never guessed.

trust

⇅ 2 sends · 18 kB → duckduckgo.com

egress ledger & air gap

Every byte that leaves is recorded by host and channel and printed under the answer; /policy airgap seals the boundary. Web pages, mail, and files are quarantined against prompt injection, and a web address the model composed after reading outside content waits for your OK.

files

delete_file → trash · /undo

files & documents

Saturn works in the folder you launch it from and reads PDF, Word, and Excel. Every write is snapshotted for /undo, and a delete goes to the Trash. Ask it to add a file to your local knowledge base and it asks first, every time. SATURN.md holds your standing instructions.

memory

remembered #12 · you said it · /memory remove 12

memory that only takes your word

Say "I'm vegetarian" and Saturn keeps it without a prompt, with one line after the answer and the command that undoes it. That happens only when the fact's words come from a sentence you typed and nothing from a web page, mail, or file has entered the conversation; anything else asks first. The first launch offers three quick questions so it knows who you are from the start. Secrets are refused, and a fact that may contradict an older one says so.

skills

/weekly-review · create_skill → always asks

skills

Write a procedure once as a markdown file and run it by typing its name. Saturn can draft one for you, and it shows you every line before it saves. That prompt appears whatever your policy says.

mcp

mcp_github_* · 12 tools · destructive

mcp servers

Connect any Model Context Protocol server from config.yaml. Its tools face the same gate as everything else and never self-declare their risk tier.

trace

run_6.json → --replay · offline

replayable runs

Every run drills down to its model passes, tool I/O, and gate decisions. Export it as JSON and replay it anywhere with saturn --replay — no database needed.

cli

saturn -q "…" · gate deny · exported ✓

headless & pipes

-p and -q run one turn for scripts and pipes; gated tools deny by default and a send is refused outright; --json for machines; the run auto-exports so the receipt names a command that replays it.

$

man saturn

the full tool and workflow reference lives in the docs →

05::next on the harness

eris.an investigation engine.

The same trust harness, pointed at open-source intelligence. Eris builds a graph of what public sources say about a subject, with a defensible record of how it got there. pre-alpha: nothing shipped yet, and the status page says exactly what is built.

input

domain · org · claim · person

one subject in. deterministic passive lookups first; a local model chooses the pivots.

output

ring graph · dossier · replayable

every edge carries source, fetch time, hash, trust tier, and confidence. every claim in the dossier cites one.

egress

ledgered · ai vendor none

inference on llama.cpp on your machine. every outbound request lands in the ledger; identity merges wait at the gate.

06::get started

run an agentyou can actually see.

One command. Under a minute. Everything on your hardware.

$ curl -fsSL saturdayai.org/install.sh | sh

made for macos · runs on linux — no account, no cloud