A local workspace for the coding agents you already use.
Savor runs Claude Code, Codex, OpenCode, Grok Build or Antigravity on your own computer and turns every task into a conversation that reports back: an acknowledgement, questions you answer in one click, the result and a live preview of what was built. On your desktop, in the browser or on your phone.
Download · Install · How it works
Under the hood: a Node daemon drives each agent CLI over its own protocol (Claude Code's stream-json, Codex's app-server JSON-RPC, the Agent Client Protocol for OpenCode and Grok Build) and gives all of them the same MCP tools to report back, ask, start other agents and run workflows. Input queues per turn; conversations can run in parallel git worktrees, workflows on cron schedules, and both can switch agents at a usage limit. State is plain files, shown by a Preact UI and reachable from your phone through an end-to-end encrypted relay. Architecture
Who builds it: Robin (robinchoice) designed the architecture, writes the specifications and reviews the results; coding agents working inside Savor write the code (how).
In numbers (v0.6.37, 26 October 2026): 425 commits and 48 releases since the first commit on 29 September 2026 · 5 agent CLIs through 4 adapters · 43 MCP tools · 191 tests in 20 test files.
A task, the agent's question and the result in the live preview, in 49 seconds. Recorded with a scripted stand-in for Claude Code and made-up projects (scripts/demo-video.mjs); MP4.
What you need: Savor brings no model and no account of its own. It drives agent CLIs you have installed and signed in to, with their subscriptions or API keys: Claude Code, Codex, OpenCode, Grok Build or Antigravity. At least one of them has to work in your terminal first.
Quick start: download the app for Linux, macOS or Windows from the latest release, start it, and add a project folder. It finds the agent CLIs on your PATH. Details and running from source are under Install, what doesn't work yet under Status.
Why Savor
- Free and open source (AGPL-3.0). No account and no cloud in between: Savor runs on your machine and uses the agent subscriptions you already have.
- Your files stay yours. Projects are ordinary folders; conversations, documents and workflows are plain files in
.savor/. - Agents that report back. Every task gets a short acknowledgement, a clear result, questions you answer in one click and suggestions for what to do next, instead of a wall of terminal output.
- See what gets built. The app your agent builds runs in a live preview beside the chat. You and the agent use the same page.
- Take it with you. Pair your phone with a QR code and keep conversations going from anywhere.
![]() |
![]() |
| Agents ask, you answer in one reply | Workflows run on a schedule, and can be chained |
![]() |
|
| The same workspace on your phone | |
- Project types: a new project is code, academic writing or a Kontor for notes and admin. A type brings the agents' instructions and its workflows. Academic writing and a Kontor ask a few questions in the new-project form, such as the citation style and the format to hand in, and Savor creates the folders and files from the answers, without an agent. Academic writing opens in three columns like NotebookLM, without terminal or conversation list: its sources (search in OpenAlex, upload or drop PDFs; a DOI brings the BibTeX entry from doi.org and the open-access PDF), one chat for the whole work, and the work with chapters, progress and the export, which checks the citations against the bibliography and runs pandoc in the chosen format and style. A chapter or PDF opens beside the chat, or in the middle for those who rather write; a Kontor gets Today with its deadlines, open tasks, inbox and the morning briefing. A code project gets two maintenance workflows, paused until its first conversation asks you whether they should run: the Uplift check, which after a model change proposes lines in
AGENTS.mdandCLAUDE.mdthat the new model no longer needs and brings back removed ones when your corrections show the old mistake again, and Leftovers, which reports uncommitted or unpushed work and open questions on weekday evenings. - Projects as tabs, each with its own color. Badges show which agents are working and which conversations need you.
- Conversations: every task gets its own agent session. You can send new messages while an agent is working; Claude Code picks them up in the running turn. Turns the agent starts on its own, for example when a background task finishes, show up as working too. You get search, filters (All / Your turn / Working / Unread), colored labels, "Finish" and a "Show finished" toggle.
- Message protocol over MCP: one acknowledgement and one conclusion per input, idempotent updates. Agents send acknowledgements, results, blocking questions, "next steps" and commit hashes. Their raw output goes to an activity log (thinking, commands, edits, tool calls, with durations).
- Questions: questions become decision records with options and a free-text answer. You answer them all in one reply. An agent's own clarifying questions (Claude's
AskUserQuestion, Codex's user input requests) show up the same way. - Queue: messages you send while the agent works wait as Queued and go out after the turn, or right away with "Stop work and send now".
- Agent picker per conversation: agent, model, reasoning level, fast mode and permissions, with the models and modes each installed agent actually offers. Save a combination as a preset. You can switch agents mid-conversation, and the new agent gets the visible history handed over.
- Attachments: images and files by picker, paste or drag-and-drop (up to 8 per message). @-mentions for files and workflows. A git branch switcher. Find in conversation with Ctrl/⌘F.
- Worktrees: a conversation can work in its own git worktree of a new branch, so several agents change the project at the same time without stepping on each other. Conversations are grouped by worktree, with commits ahead and uncommitted changes at a glance, Merge back into the project and Delete. Once all its conversations are finished and its work is merged with nothing left uncommitted, a worktree and its branch go by themselves. Agents can start conversations in a worktree too.
- Fan-out: send one prompt to several agents or agent/model combinations at once, each in a new worktree of its own. Compare their answers, changed files, diffstat and previews side by side, then merge the one you pick and delete the other worktrees in the same step.
- Commit diffs: commit hashes in agent messages open the commit: changed files with +/− and the patch.
- Approvals: permission prompts from Claude Code, Codex and ACP agents appear in the conversation with the agent's own options (Allow, Always allow, Allow for this session, Deny).
- Files: a project file browser with a code editor (CodeMirror, syntax highlighting for the usual languages, Ctrl/⌘S), a rich-text editor for markdown files with a switch to the source, read-only previews of PDF, Word (DOCX) and Excel (XLSX) files, CSV as a table, and markdown documents that both you and the agents write and that save as you type.
- Workflows: saved prompts on a schedule (presets such as every weekday at 9:00, or any cron expression), which can be chained and grouped into collections. Each run starts a new conversation and is listed under its workflow with its result. A run that was due while Savor was not running is caught up at the next start, and a scheduled time is skipped while the run before it is still open. A workflow can also run when the model changes: once each time the project's default agent runs on a new model, and not again until the next one. A workflow can get a button in the top bar that runs it now, in place of its next scheduled run within 12 hours. A gallery of 24 ready-made workflows, from a morning briefing to a citation check, fills the editor for you to adjust and save.
- All projects: an overview that starts with what waits for you in any project, with questions and approvals answered in place, then what agents work on, new results and the next workflow runs. An inbox with the open conversations of every project beside the chosen one, filtered by the type of their latest notice (question, result, workflow run, error, CI, message), with several marked read at once, and a board with a backlog of what to start later (your own items and items agents put there with
add_to_backlog) next to what agents are doing. - Import: the Claude Code and Codex sessions you ran in a project folder before Savor become conversations, and continue with the same agent session.
- Project settings:
ROLE.mdinstructions for every agent, verbosity, pause (skips scheduled runs), color and default agent. - Terminal: a panel below the project with one shell per project folder and worktree, for a quick
git statusor test run. It follows the open conversation into its worktree, and shells keep running while the panel is closed, until Savor stops. Paired devices only get it once you turn it on for them at your computer. - Background processes: agents register the dev servers they start. Savor watches the PIDs, shows logs and can stop them.
- Live preview: the app the agent built runs in a headless Chromium next to the chat, with a persistent browser profile per project so logins survive restarts. You see exactly the page the agent controls, and your clicks, typing and scrolling are forwarded to it. The picker lets you point at an element ("make this bigger"), and its selector and styles go along with your next message.
- Devices: pair a phone or another computer with a QR code. Each device has its own revocable key. A phone paired with several computers switches between them in its account menu. Requests from devices are marked remote, and agents treat them with extra care.
- Notifications when an agent finishes, needs an answer or asks for approval, plus an unread count in the tab title and on the app icon. Paired phones get a push only when the notice stays unseen on your other devices for a while (5 minutes by default, questions after one), and at once when Savor is open nowhere. A question can be answered from the notification, with a few seconds to undo, and a notice seen on one device disappears from the others.
- Keyboard shortcuts you set per device for new conversation, Next, the composer, voice input, stop, finish, tabs, browser, terminal and project tabs. Savor starts without any; the setup and the settings offer a suggested set.
- Keep awake toggle, dark and light theme, English and German (follows the system, switchable under Appearance).
Everything lives in plain files: ~/.savor/state.json holds projects, tokens and devices, each project gets a .savor/ directory, and worktrees live under ~/.savor/worktrees/.
Desktop app: download the AppImage (Linux), dmg (macOS) or exe (Windows) from the Releases page. The app starts its own daemon, finds agent CLIs through your login shell's PATH, downloads Chromium for the preview on first use, and updates itself from new releases. You still need at least one logged-in agent CLI (claude, codex, …).
- Linux:
chmod +x Savor-<version>.AppImage && ./Savor-<version>.AppImage. No extra flags are needed: where Chromium's sandbox can't use user namespaces, for example on Ubuntu 24.04 and later because of AppArmor, the AppImage starts itself with--no-sandbox. - macOS:
Savor-<version>-arm64.dmgis for Apple Silicon,Savor-<version>-x64.dmgfor Intel. The builds are ad-hoc signed and not notarized, so macOS blocks the first launch: open System Settings → Privacy & Security and click Open Anyway. Up to macOS 14, a right-click → Open works too. The app only updates itself once builds are signed with a Developer ID. - Windows builds are not code-signed yet: SmartScreen asks once.
From source (Node ≥ 22.12):
git clone https://github.com/robinchoice/savor.git && cd savor
npm install # also builds the web UI and the server bundle
npx playwright-core install chromium # browser for the preview
npm startOpen the printed http://localhost:4317/?token=… link once. It sets a cookie, and after that http://localhost:4317 is enough.
Desktop window from source: cd desktop && npm install && npm start. The window starts its own daemon unless one is already running on SAVOR_PORT, and stops that daemon again when you close it. On Ubuntu 24.04 and later, either run sudo chown root:root node_modules/electron/dist/chrome-sandbox && sudo chmod 4755 node_modules/electron/dist/chrome-sandbox, or start it with npm start -- --no-sandbox.
As a background service (Linux, systemd user unit), so Savor is reachable from your phone without an open window:
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/savor.service <<UNIT
[Unit]
Description=Savor
# A daemon that keeps crashing stops after five tries in five minutes instead of looping.
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
ExecStart=$(command -v node) $PWD/dist/server/index.mjs
Environment=PATH=$PATH
Restart=on-failure
# The kernel ending a browser or agent for lack of memory leaves the daemon running.
OOMPolicy=continue
[Install]
WantedBy=default.target
UNIT
systemctl --user enable --now savor
journalctl --user -u savor | grep token # the login linkOpen Devices & remote access from the avatar menu. Your desktop has to stay awake while you're away, which the coffee-cup toggle takes care of. There are two ways in:
Through a relay (no VPN, works on mobile data). Enter a relay URL, click Connect, then Pair a device and scan the QR code with your phone. Use "Add to Home Screen" on the phone, or the app (in testing through TestFlight and Play):
-
iOS (
mobile/ios, Capacitor): bundles the web client, so the relay can't change it, and scans the QR code itself. It remembers each computer's relay. No push notifications yet: they need the relay to pass them on to Apple. -
Android (
mobile/android, Bubblewrap): a Trusted Web Activity of the relay atsavor.diespaetzles.lol, so it is the web app with its Web Push. The relay proves the app is its own with/.well-known/assetlinks.json. -
Traffic between the device and your computer is end-to-end encrypted (X25519 key exchange with forward secrecy, ChaCha20-Poly1305, see
shared/tunnel.ts). The relay forwards ciphertext. It sees your computer's public key, connection times and message sizes. It does not see your conversations, files or which of your devices is connecting. -
Pairing uses the computer's public key and a one-time code from the QR code, so the phone knows it's talking to your computer and not to the relay.
-
The terminal is a shell on your computer, so paired devices don't get it by default. Turn it on per device at your computer under Devices & remote access → Paired devices; turning it off again ends that device's open terminals. Without it, a device also can't edit git's config or the agents' project settings (
.git/,.claude/,.mcp.jsonand the like), which run commands without asking. -
Every paired device has its own key and can be revoked, which cuts its tunnel and open streams immediately. In the browser, the device key is a non-extractable WebCrypto key: scripts can use it but cannot read it out.
-
The relay authenticates daemons by their key, so nobody else can take over your computer's relay address. It closes connections that don't authenticate or start a handshake within 10 seconds, and it limits connections per IP, per computer and in total.
-
The relay and Savor send a strict Content Security Policy and other security headers.
-
One caveat: the relay also serves the web app to the phone, and a malicious relay could serve a modified app. Run your own relay, or use one run by someone you trust.
Run a relay on any server with Node ≥ 22.12, behind HTTPS (for example with Caddy):
git clone https://github.com/robinchoice/savor.git && cd savor
npm install
RELAY_TRUST_PROXY=1 RELAY_PORT=8787 npm run relay# Caddyfile
relay.example.com {
reverse_proxy localhost:8787
}
Directly over your own network or a VPN such as Tailscale or WireGuard. Savor binds to 127.0.0.1 by default:
SAVOR_HOST=0.0.0.0 SAVOR_PUBLIC_URL=http://my-desktop.tailnet.ts.net:4317 npm startWithout a connected relay, the pairing QR code points at SAVOR_PUBLIC_URL.
The desktop app counts its installations with one anonymous ping a day to the relay at savor.diespaetzles.lol. It sends exactly this:
{ "id": "random, made on your computer", "version": "0.6.20", "platform": "linux", "internal": false }The ID is 16 random bytes, unrelated to your computer or anything else. internal is true only on the maker's own computers. Nothing else is sent: no projects, no conversations, no names. The relay stores the ID per day without IP addresses, deletes IDs it hasn't seen for 90 days and keeps only weekly sums after that (relay/usage.ts, server/usage.ts). Switch it off in the account menu under App settings → Count this installation. Savor run from source or with npm start sends nothing.
To mark an installation as internal, set "internal": true in ~/.savor/state.json and restart Savor.
| Variable | Default | |
|---|---|---|
SAVOR_PORT |
4317 |
HTTP port |
SAVOR_HOST |
127.0.0.1 |
Bind address |
SAVOR_PUBLIC_URL |
http://localhost:$SAVOR_PORT |
Base for links agents post and pairing links |
SAVOR_HOME |
~/.savor |
Global state |
RELAY_PORT |
8787 |
Relay only: HTTP/WebSocket port |
RELAY_WEB_DIR |
dist/web |
Relay only: web app to serve |
RELAY_TRUST_PROXY |
off | Relay only: set to 1 behind a reverse proxy, so rate limits use X-Forwarded-For |
RELAY_MAX_DAEMONS |
5000 |
Relay only: computers that can be connected at once |
RELAY_DB |
in memory | Relay only: SQLite file for the installation counts |
RELAY_USAGE_TOKEN |
– | Relay only: bearer token for GET /usage, the weekly installation counts |
SAVOR_USAGE_URL |
set by the desktop app | Where the daily usage ping goes; unset, nothing is sent |
SAVOR_CHROMIUM |
Playwright Chromium, then system Chrome/Chromium | Browser for the preview |
SAVOR_CLAUDE_BIN, SAVOR_CODEX_BIN, SAVOR_OPENCODE_BIN, SAVOR_GROK_BIN, SAVOR_ANTIGRAVITY_BIN |
claude, codex, opencode, grok, agy |
Agent binaries |
SAVOR_ANTIGRAVITY_HOME |
~/.gemini |
Where agy keeps its settings |
Workflow runs and the conversations they start don't wait at a usage limit: they go on with the next agent (Codex, Antigravity, OpenCode). With "Switch agents at usage limits" on (This computer → Agents), every conversation goes on with the agents listed there instead, each with its own model, effort and permissions: agents at a known limit are skipped before a request starts, and once the limit of the agent a conversation had resets, its next request goes back to it. With API credit, Claude Code can go on with that first. Name an env file and the variable in it that holds the key in ~/.savor/state.json, never the key itself:
"apiCredit": { "envFile": "~/.secrets", "variable": "ANTHROPIC_API_KEY", "headers": "anthropic-workspace-id: wrkspc_…", "budgetUsd": 15 }Savor reads the key from the file (NAME=value or export NAME=value lines) each time it starts Claude Code on API credit and puts it only into that process's environment, with headers as ANTHROPIC_CUSTOM_HEADERS when set. Each takeover may spend budgetUsd (default 15); when the credit is used up, the budget reached or the key refused, the next agent takes over. Without that setting, the user's own conversations wait for the reset.
Antigravity runs agy --print once per turn and continues the conversation with --conversation. agy reads MCP servers only from its own settings, so Savor adds a savor stdio server to ~/.gemini/config/mcp_config.json that forwards to the conversation it runs for, and allows its tools with mcp(savor/*) in ~/.gemini/antigravity-cli/settings.json. Headless agy cannot ask for approval: whatever the chosen mode doesn't allow is denied, and the activity log names it.
flowchart TD
In["Input: UI, phone, scheduled workflow, another agent"] --> Q["Turn and queue<br/>agents.ts"]
Q --> H["Session host<br/>session.ts"]
H --> C["Claude Code<br/>stream-json<br/>claude.ts"]
H --> X["Codex<br/>app-server JSON-RPC<br/>codex.ts"]
H --> A["OpenCode, Grok Build<br/>Agent Client Protocol<br/>acp.ts"]
H --> G["Antigravity<br/>agy --print<br/>antigravity.ts"]
C & X & A & G --> M["MCP tools: acknowledge, ask, conclude,<br/>start agents, run workflows<br/>mcp.ts"]
H -->|approvals, activity log| S
M --> S[("Messages, decisions, documents<br/>plain files in .savor/<br/>store.ts")]
S -->|SSE events| UI["Web UI and desktop app"]
S -->|end-to-end encrypted tunnel| R["Relay → phone"]
server/
index.ts HTTP API, SSE events, static UI, MCP endpoint
agents.ts turns, the queue, approvals and questions
session.ts what every agent adapter gets (Host) and provides (Session), protocol prompt, activity log
claude.ts Claude Code over stream-json with stdio permission prompts
codex.ts Codex over the app-server protocol (JSON-RPC)
acp.ts OpenCode and Grok Build over the Agent Client Protocol
antigravity.ts Antigravity: one `agy --print` run per turn, stream-json, MCP through a stdio bridge
jsonrpc.ts newline-delimited JSON-RPC over stdio
providers.ts what each agent offers, and whether it is installed and signed in
mcp.ts MCP tools the agents call
store.ts file storage
git.ts worktrees, merging, commit diffs
import.ts Claude Code and Codex session transcripts as conversations
devices.ts owner token, device pairing, request origin
scheduler.ts cron workflows and chains (croner)
processes.ts PID watcher
browser.ts shared headless preview with screencast (playwright-core)
files.ts project file access
awake.ts keep-awake inhibitor
relay-client.ts outbound relay connection, serves tunneled devices
usage.ts the anonymous daily usage ping
shared/
tunnel.ts end-to-end encryption for the relay tunnel (noble crypto)
relay/
server.ts the relay: daemon login, device routing, serves the web app
usage.ts counts installations from their daily ping
web/ Preact PWA (CodeMirror and TipTap load on demand for the editors)
recipes/ workflow gallery: markdown with front matter, bundled into the UI
desktop/ Electron shell and installers (electron-builder)
mobile/ iOS app (Capacitor, capacitor.config.json in the root), Android app (Trusted Web Activity)
test/ end-to-end tests with a fake agent
- Every conversation gets one long-lived agent process. It stays alive while the conversation owns background processes and closes 5 minutes after the last activity. A change of agent, model, effort, fast mode or permissions restarts it and resumes the agent's own session.
- Claude Code runs as
claude -p --input-format stream-jsonwith--permission-prompts host --permission-prompt-tool stdio: permission prompts andAskUserQuestionarrive as control requests on stdout and are answered on stdin. "Always allow" writes the rule Claude suggests to.claude/settings.local.json. - Codex runs as
codex app-server(JSON-RPC over stdio):thread/start,turn/start,turn/interrupt, approvals throughitem/commandExecution/requestApprovalanditem/fileChange/requestApproval, questions throughitem/tool/requestUserInput. The permission modes map to Codex's sandbox and approval policy; models and effort levels come frommodel/list. - OpenCode (
opencode acp) and Grok Build (grok agent stdio) speak the Agent Client Protocol:session/new,session/prompt, progress throughsession/update, approvals throughsession/request_permission, interrupts throughsession/cancel. Grok Build ends a plan with an_x.ai/exit_plan_moderequest, answered with{ outcome: "approved" }or, to keep planning, any other outcome.
Project layout:
<project>/.savor/
project.json, ROLE.md, processes.json, backlog.json
actions.jsonl what agents changed through Savor's tools, and what they tried
threads/<id>/thread.json, messages.jsonl, activity.jsonl, attachments/
decisions/<id>.json
documents/<id>.md, <id>.json a document and where its last change came from
workflows/<id>.json
~/.savor/worktrees/<project id>/<branch>/ git worktrees of conversations
A conversation in a worktree runs its agent there: the agent's working directory, the branch switcher and registered processes all refer to the worktree. Deleting a worktree removes it and its branch; its conversations stay and continue in the project folder with a fresh agent session that gets the visible history handed over.
A workflow may set preflight through create_workflow / update_workflow or the workflow REST API:
{ "preflight": { "file": ".workflow-checks/night.json", "maxAgeSeconds": 60 } }An existing, independently authorized script writes that project-relative file atomically before the scheduled run. Savor only reads it; it never launches a command, installs a producer or grants permissions. Only .workflow-checks/<name>.json is accepted (regular files, no directory/file symlinks or hard links, at most 64 KiB). Keep one overwritten file per check. Removing preflight with null restores the ordinary start behavior.
{
"checkedAt": "2026-10-17T15:00:00.000Z",
"status": "ok",
"work": false,
"pending": false,
"reason": "Versions and relevant commits unchanged; no open counterchecks.",
"evidence": ["versions 1.2.3 / 4.5.6, commit abc123, countercheck queue empty"],
"followUp": []
}All fields are required. status: "ok" starts the agent when work or pending is true; both false document a skipped start without calling a model. pending: true must include follow-up work and takes precedence over unchanged versions. A producer must check both changed inputs and unresolved work, refresh its signal before each due time, and invalidate it when relevant inputs change. The timestamp is a freshness limit, not a substitute for checking those inputs. Waiting for another batch is an explicit no-work decision with evidence, or blocked if a prerequisite is missing. Producer errors use failed, never work: false. blocked and failed require followUp. Missing, expired or future-dated files block; unreadable or malformed files fail. Neither starts an agent. The same origin rules as workflow prompts apply to changes to the preflight configuration.
Each run keeps step results in its existing conversation metadata. begin_workflow_step({id}) checks a linked step before its prompt is executed; run: false means stop that step. Steps already settled do not run twice, including cycles. Agents use report_workflow_result({id, result: {status, reason, evidence, followUp}}):
| Status | Meaning |
|---|---|
successful |
Verified outcome, no follow-up left. |
partial |
Some work done; follow-up remains, including delegation awaiting verification. |
blocked |
A prerequisite is missing; follow-up names what unblocks it. |
skipped |
Deliberately no work, with evidence and no unresolved follow-up. |
waiting |
Intentionally waiting for a user decision; scheduled starts wait too. |
failed |
A check or step failed; follow-up names the repair. |
unknown |
Derived when no business result was reported; a finished turn is insufficient. |
Evidence is required for reported results; unresolved statuses also require follow-up. Starting a conversation, sending it work or starting another workflow records delegation as partial. Closing that conversation cannot settle the step: the parent must provide verifiedDelegations: [{threadId, evidence}] with the verified outcome. A conclusion with questions records intentional waiting for unfinished steps. It preserves an already verified outcome. A human reply changes waiting to partial until the outcome is verified. Closing the parent conversation does not erase blocked or partial results. For workflows with a preflight, retrying an unresolved run reuses its conversation, rechecks its preflight and preserves remote origin. An explicit manual run may resume waiting when no user question is still open. A no-work signal cannot close work the agent already started. Workflows without a preflight keep their existing start behavior, including fresh runs after delegation and after a conversation was closed; previous business outcomes stay visible. Completed checks with no agent start are archived so idle runs do not fill the open conversation list. An early check consumes the upcoming scheduled slot only when an agent actually starts.
list_workflow_runs({id}), read_conversation and GET /api/projects/:pid/workflows/:id/runs expose the data. The existing workflow list shows turn lifecycle and business outcome separately, with reasons and follow-up; evidence is also in the row's tooltip. Runs expose reported usd / tokens, measured workedMs and, when steps have results, wall-clock elapsedMs. Missing values are omitted, not zero. Monthly reported sums include counts of runs with unknown USD/token usage. modelStarted: false identifies starts avoided by the gate; it makes no claim about hypothetical token or money savings. attempts keeps the latest 200 check/start/resume/restart/human-input events with timestamps; attemptCounts preserves cumulative counts. A human input is a measurable interaction, not proof of a rescue. Existing restart recovery continues the same request, rather than repeating external commands automatically. Seven-day evaluation can read these fields through existing reporting workflows.
npm run typecheck
npm test # end-to-end: real daemon + UI in headless Chromium, test/fake-claude.mjs as the agent
npm run dev:web # Vite dev server for the UI, proxies /api to a daemon on :4317
cd desktop && npm run dist # local installer build (AppImage on Linux)CI runs typecheck and the end-to-end tests on every push. secrets.yml scans every push on every branch and pull requests from forks for secrets with gitleaks (default rules, --redact keeps found values out of the public log); single false positives go into .gitleaksignore by fingerprint. Pushing a tag like v0.2.0 builds the desktop app for Linux, macOS and Windows and publishes it as a GitHub release, which installed apps pick up as an update. The same tag builds the phone apps (mobile.yml) and hands them to the testers in TestFlight and Play.
Early: version 0.x, first released in September 2026, with releases several times a week. Savor is used every day for real work, but expect rough edges. Known gaps and limits:
- One person, one computer: there are no user accounts, teams or shared projects. Other devices are your own, paired with a QR code.
- Savor is not a sandbox. Agents run as your user with the permissions you give them in the agent picker, and Savor shows their approval prompts.
- The desktop builds are not notarized (macOS) or code-signed (Windows) yet, and macOS builds don't update themselves until they are.
- Antigravity doesn't work on Windows yet.
- The phone apps are in closed testing (TestFlight, Play's internal test). On the phone, use the web app through a relay or your own network.
- There is no public relay instance yet: run your own (see above) or use a direct connection.
- A browser can pair with several computers but talks to one at a time, and only that one sends it notifications.
Robin at Pleasance sets the direction: architecture, specifications and review. Coding agents working inside Savor write the code. Every change goes through CI, which runs the end-to-end tests against a real daemon and UI. Releases ship several times a week, and installed apps update themselves.
Every Monday, when Claude Code, Codex, OpenCode, Grok Build or Antigravity has a new version, a check installs the newest ones and runs a real conversation with each through Savor (a prompt, a permission request, an interrupt). A change in their protocols that breaks Savor is diagnosed and handed to an agent as a fix conversation. When the agents move to a new model, an uplift check goes through Savor's own instructions to agents, project types and workflow gallery and proposes what the new model no longer needs.
If Savor ever stops, you lose nothing:
- Your code is in your own git repository.
- Conversations, documents and the backlog are plain files in
.savor/inside your project. - Claude Code and Codex sessions stay regular sessions of those CLIs, so
claude --resumeorcodex resumepick them up without Savor. - AGPL-3.0 lets anyone fork and continue it, and
AGENTS.mdgives their agents what they need to start.
AGPL-3.0-or-later
The app ships the typefaces Geist and Geist Mono by The Geist Project Authors under the SIL Open Font License 1.1. The license text is in web/public/geist-license.txt and is part of every build.



