cd /news/developer-tools/sauron-a-free-and-open-source-termin… · home topics developer-tools article
[ARTICLE · art-123944] src=github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Sauron: A free and open source terminal development environment

Matt Olson released Sauron 0.1.0, a free and open-source terminal development environment (TDE) for macOS that manages multiple coding agents across multiple projects using tmux sessions, with features like background agents, worktrees, and commit attribution. The app, available as a signed and notarized DMG for Apple silicon Macs on macOS 15 or later, requires tmux, git, and at least one agent CLI such as Claude or Codex.

by read7 min views1 publishedSep 8, 2026
Sauron: A free and open source terminal development environment
Image: Michielbdejong (auto-discovered)

A "super terminal" desktop app for running a lot of coding agents across a lot of projects, built on tmux.

I like running agents in the terminal. Claude Code, Codex, Opencode, Picode, local AI, cloud providers, etc. What I did not like was keeping track of fifteen of them across six repositories. Which ones are waiting on me? What did that one agent commit? Where was I on this project three weeks ago? Sauron is the thing I built to answer those questions without giving up the terminal. It is not quite an IDE and it is not quite a terminal. I call it a TDE (terminal development environment).

It is free and open source and always will be!

Download: Sauron-0.1.0-arm64.dmg for Apple silicon Macs on macOS 15 or later, signed and notarized. Other builds are on the releases page. It needs tmux, git, and at least one agent CLI such as claude or codex on your PATH.

Every session Sauron starts is a tmux session. Quit the app and they keep running. Reboot and resume them. Attach from any terminal with tmux attach (there is a button that copies the command). Nothing you run is trapped inside the app. Sauron can also see sessions that are started in external terminal. The principal is low coupling between Sauron and your tmux sessions.

Sauron does not include skills, a task framework, a planning routine, or instructions for your agents. It does not put anything in your repository except a post-commit hook, an entry in .git/info/exclude, and the ignored .sauron/ directory that entry covers. An agent is a profile: an executable and its arguments. Claude and Codex come preconfigured; add anything else that runs in a terminal, including a plain shell. Run agents the way you already do, with the flags you already use. Sauron just keeps track of them.

Run Claude, Codex, Openrouter, and a local model side by side under the same project. Fork a session into a worktree. Hand a session's work to a different agent: Sauron writes a briefing from the recent transcript, the session's commits, and the state of the working tree, and starts the other agent with it. No model in the loop, so it takes a fraction of a second. Hit a usage limit on one vendor, carry on with another.

Sauron allows you to define "background" agents and attach them to any project. Background agetns run headless in a fresh worktree on its own branch, manually, on a schedule, or after commits with a cooldown, and it runs whether or not the app is open. When it finishes, its commits wait on the agent's page with a diff viewer and Merge. Or they can run on your main repo and just do whatever.

A post-commit hook records which session was behind each commit, so an agent's work is never just "Matt Olson, 4d ago" in the log. Each session shows its last commit under its name in the sidebar. The Commits pane lists everything a session committed, with the diff, or switches to the whole project so you can see who did what across every agent and branch. It works for you too: commits you make by hand inside a Sauron terminal are attributed to that terminal. The hook only ever exits 0, so it cannot break a commit.

  • Project summaries. A built-in background agent rewrites a short status for each project after commits: what it is, what changed, what is open or blocked. It lives in<project>/.sauron/status.json , kept out of git, where your other agents can read it too.
  • Sessions you started elsewhere. Claude and Codex sessions launched from a terminal show up under their project with a live transcript. Import one to bring it under Sauron.
  • Worktrees. Start a session in a fresh worktree on its own branch so parallel agents do not step on each other. The header shows the branch and checkout and updates as they change.
  • A supervisor agent , off by default. A long-lived agent you chat with that can start and message workers through the CLI.

Electron, TypeScript, React, xterm.js, node-pty, built with electron-vite. Sessions run inside tmux; commit attribution lives in a SQLite database alongside the app's config.

Requires Node 22+, pnpm, and on the machine: tmux, git, claude (Codex optional).

pnpm install          # also rebuilds node-pty for Electron
pnpm dev              # hot-re development run
scripts/app.sh             # build and launch the unpackaged dev build, detached
scripts/app.sh --packaged  # build and launch dist/mac-arm64/Sauron.app (proper name and icon; slower)
scripts/install-launcher.sh  # installs `sauron-dev` on PATH and ~/Desktop/Sauron.app, both of which run scripts/app.sh
pnpm test             # Vitest
pnpm typecheck
pnpm package          # unsigned Sauron.app in dist/

pnpm dist builds a signed, notarized DMG (and zip) into dist/. It needs two things set up once on the machine that builds:

  1. A Developer ID Application certificate in the login keychain, from Xcode > Settings > Accounts > Manage Certificates, or from developer.apple.com.
  2. Notarization credentials stored as a keychain profile named sauron-notary : It asks for an app-specific password, made at appleid.apple.com.
xcrun notarytool store-credentials sauron-notary --apple-id you@example.com --team-id TEAMID

The script refuses to run without both. scripts/dist.sh --unsigned builds the same DMG unsigned for a local check; other Macs will only open that one via right-click > Open. Signing uses the hardened runtime with the entitlements in build/entitlements.mac.plist (JIT and unsigned executable memory for Electron, library validation off for node-pty).

  • ⌘O add a project,⌘, preferences,⌘K quick switcher,⌘⇧] /⌘⇧[ next and previous live session. Right-click projects, sessions, and the supervisor for actions.
  • Add a project by dragging a git repository onto the window, pressing ⌘O, or from the shell: open -a Sauron ~/code/my-repo (packaged app) orscripts/sauron projects add ~/code/my-repo .
  • The supervisor's home is ~/Library/Application Support/Sauron/master ; Sauron writes bothCLAUDE.md andAGENTS.md there so agents of either convention receive its instructions.
  • Logs: ~/Library/Logs/Sauron/main.log (Preferences > Reveal Logs).
  • docs/QA.md is the manual checklist;scripts/smoke.sh is the end-to-end check against a running app.TODOS.md tracks open items.

scripts/sauron talks to the running app over ~/Library/Application Support/Sauron/sauron.sock. The supervisor agent uses the same commands to drive workers.

scripts/sauron ping
scripts/sauron projects [add <dir>]
scripts/sauron sessions [--project <name|id>]
scripts/sauron launch --project <name|id> [--tool claude|codex|shell|<profile>] [--prompt "..."] [--worktree [<branch>]]
scripts/sauron send --session <id> --text "..."
scripts/sauron stop | resume | close | hide --session <id>
scripts/sauron fork --session <id>
scripts/sauron handoff --session <id> --tool <profile>
scripts/sauron rename --session <id> --title "..."
scripts/sauron worktrees --project <name|id> [remove --path <dir> [--force]]
scripts/sauron status refresh --project <name|id>   # run the Project summarizer now
scripts/sauron status set --project <name|id> --summary "..." [--details "..."] [--update "..."] [--todo "..."]
scripts/sauron status get|set ...                # also work with the app closed, straight from the project's status file
scripts/sauron job run|list|merge|discard ...    # background agent runs; `sauron tick` is what launchd calls every minute
scripts/sauron master                            # start the supervisor
scripts/sauron select --project <name|id> [--job <agent id>] | --session <id> | --document <path>

Set SAURON_TOOL_CLAUDE, SAURON_TOOL_CODEX, SAURON_TOOL_TMUX, or SAURON_TOOL_GIT to override a tool's path; the value none simulates a missing tool.

Preferences > Agent profiles lets you add any interactive CLI agent by giving it an id, name, executable, and arguments. Arguments are stored as an array and support {prompt}, {cwd}, {sessionId}, and {sauronBin} placeholders. If {prompt} is absent, an initial prompt is appended as the final argument. Custom agents run in the same persistent tmux terminals as the built-ins and can be handoff targets; transcript discovery, hooks, forking, and resume remain built-in integrations for Claude and Codex.

An agent profile may define forkCommand as an argument array. It supports the same placeholders plus {sourceSessionId}. Fork and Import only appear for sessions with a known CLI session id whose profile has a non-empty fork command. Claude and Codex include fork commands by default.

Claude and Codex are themselves editable profiles. Their default profile arguments bypass permission prompts; remove those arguments in Preferences if you want the CLIs to prompt normally.

The supervisor agent is selected separately in Preferences. Its extra arguments can select a model (for example --model opus for a Claude profile).

The Project summarizer's prompt is jobs/project-summarizer.md beside config.json, seeded on first launch and then yours to edit. It supports {projectName}, {projectId}, {projectPath}, {branch}, {jobName} and {previousSummaryUpdatedAt}. Its trigger and cooldown are edited like any background agent's, globally in Preferences or per project with Configure….

When a project is added, Sauron installs a post-commit hook into it (an existing hook is kept and chained to). The hook inherits the environment of whatever invoked git, so it sees SAURON_SESSION_ID exactly when the commit came from a managed session, and reports the commit to the app over the control socket; otherwise it does nothing. Every path in the hook exits 0, so a Sauron problem can never fail a commit. Linked worktrees share the main checkout's hooks, so one install covers every worktree Sauron creates. Removing a project removes the hook and restores whatever it displaced.

── more in #developer-tools 4 stories · sorted by recency
── more on @matt olson 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/sauron-a-free-and-op…] indexed:0 read:7min 2026-09-08 ·