Skip to content

Changelog#

All notable changes to this project are documented here. The format follows Keep a Changelog and the project uses Semantic Versioning.

Unreleased#

Added#

  • .worktreeinclude: list the gitignored files a fresh worktree needs (.env, local config, certificates) in .gitignore syntax, and every agent worktree gets a copy from your main checkout. Only files git ignores are copied. It's the file Claude Code and Conductor already read, so repositories set up for them work as they are.
  • Open a pull request from an agent's worktree: optimus wt pr W [--title T] [--draft], PR in the browser, POST /api/windows/{id}/pr. It commits pending work, pushes the branch and opens a pull request into the branch Merge would land in, with the GitHub CLI if it's installed; otherwise it gives the GitHub, GitLab or Bitbucket page that opens one.
  • New-session folder picker that finds every project under your home folder, not only folders that already have sessions: git repos and folders with a project manifest (crawled in the background, cached, skipping dependencies and build output), ranked by name match and agent history. Type ~/ or / to browse like a shell; ↑↓ to choose, Enter to pick, Tab or › to open a folder. GET /api/dirs?q=.
  • The terminal dashboard's new-session folder picker (n) uses the same search: every project under home, not only folders with past sessions, ranked the same way; ~/, / or ./ browse, Tab opens the highlighted folder, and the typed folder itself is the first row.
  • optimus <command> -h and optimus help <command> show that command's usage and flags. Before, -h printed nothing, and a mistyped flag printed only the error.

Changed#

  • Browser: a folder typed relative (dev/app) is found from your home folder, as the picker completes it, not from wherever the dashboard was started; starting with a search term you didn't pick from (optim, then Ctrl+Enter) uses the highlighted match.
  • Browser: the message box's all (broadcast) unticks after each broadcast, so the next message goes to the selected agent only.
  • Browser: a banner says when the dashboard can't reach optimus, instead of showing a frozen fleet as if nothing changed.

Fixed#

  • Browser: errors raised while a dialog was open (New session, Handoff) appeared behind its backdrop, blurred and unread.
  • Browser: Enter in the New session dialog's name field closed the dialog and dropped everything typed, instead of starting the session.
  • Browser: a message that failed to send was cleared anyway and reported as sent; it now stays in the box to retry.
  • Phone: tapping a key button (Esc, ↵, 1, y…) opened the on-screen keyboard over them; focusing a text field zoomed the page on iOS; a worktree agent's actions ran off the screen, hiding Stop; the Sessions table scrolled sideways. Key buttons, folder rows and the folder picker's › are now finger-sized, and keyboard-only hints are hidden on touch screens.
  • Browser: Handoff offered to hand a session into its own window, and Esc on the login dialog left an empty dashboard.
  • Every agent ran in the cgroup of whatever started the tmux server, so the out-of-memory killer (which takes whole cgroups) ended all sessions at once and they came back when the supervisor restarted — sessions "appearing and disappearing". On Linux with a reachable systemd user manager, each agent now runs in its own optimus-agent-*.scope, so an OOM kill ends one session and restarting the UI ends none. OPTIMUS_NO_SCOPE=1 turns it off.
  • A window whose transcript wasn't written yet (before its first message) borrowed the newest other session in the same folder: its title, cost, transcript and handoff showed someone else's session, so two sessions in one folder looked like one. A window that knows its session id no longer guesses.
  • After /clear, /resume or a fork inside a window, the fleet kept showing the old session. The Claude hook now retags the window with the session actually running.
  • An agent outside optimus that had just started (still at Claude's folder-trust prompt, before Claude writes ~/.claude/sessions/<pid>.json) showed "session unknown". A resumed or pre-assigned session is now recognised from its command line (--resume, -r, --session-id, codex resume), and when a session has to be guessed, one another process is already writing is never assigned twice.
  • Resuming a session that is already running in another terminal started a second process on the same transcript; it now refuses and points to take-over.
  • Resuming such a session from the terminal dashboard now offers to take it over in place of an error, and the CLI error names the command (optimus takeover <pid>).
  • The terminal dashboard's key hints were cut off on screens narrower than ~200 columns, hiding ? help and q quit; those now always show and the other hints are ordered by use.
  • optimus new, resume, takeover, handoff --to and the agent shortcuts reported tmux's window id (@3) while optimus ps and the dashboard show window numbers; they now print the number and name, and how to attach.
  • optimus kill and peek without a window said no optimus window ""; they now show their usage, and every window command given an unknown window points to optimus ps.
  • Docs: per-agent systemd scopes and OPTIMUS_NO_SCOPE, the folder search, the resume guard, windows following /clear and /resume, the dashboard keys missing from the key table, and agents outside optimus (the FAQ still said they couldn't be driven).
  • The notifier lock was dropped at the first garbage collection (nothing kept its file open), so every dashboard, TUI and optimus watch ran its own watcher: duplicate notifications, and each one polling tmux every two seconds. The lock now lasts as long as the process.
  • /api/state ran three git commands per worktree window on every poll (every open tab, every 2.5 s). Worktree diff stats are now reused for 10 s and dropped on merge or discard: with three worktree windows a poll went from 160 ms to 52 ms (median) and from ~180 ms to ~95 ms of CPU.
  • A launch or fan-out folder typed as ~name became $HOME + name (a sibling of your home folder); ~ now only means your home folder, and fan-out checks the folder exists like launch does.

Security#

  • The dashboard sends a Content-Security-Policy: scripts only from the dashboard itself (no inline script, no eval), no plugins, no framing, connections only back to the dashboard. Any script running in the page can type into an agent's terminal, so this is the backstop for a missed escape in rendered transcript text.
  • External pane ids (ext:<socket>:<pane>) arrive in API URLs and were joined to the tmux directory as given, so an encoded ../ could point tmux -S at any socket path. A socket must now be a plain name in your tmux directory and a pane a %N id; anything else is refused instead of falling through to the optimus server.
  • Handoff documents quote the conversation (pasted keys included) but were written world-readable (0644 in a 0755 folder); they are now 0600 in a 0700 folder, and an existing folder is tightened.
  • The installer installed a release binary without verification when checksums.txt could not be downloaded; a missing checksum now aborts the install like a wrong one.
  • Taking over an agent always failed with "already running … take it over instead": the stopped agent was still in the 2-second process cache when its session resumed. Exited agents now leave the list at once, and take-over checks the pid still belongs to that agent before signalling it.
  • After /clear or /resume, a window showed exited and kept the old session until its next prompt. The Claude hook now also listens for SessionStart, ignores the SessionEnd of a /clear, and a live window is never shown as exited.
  • A Claude killed outright (out of memory, SIGKILL) left its ~/.claude/sessions/<pid>.json behind, and once the pid was reused that dead session showed as running, or was pinned on another Claude. Entries now count only while the process start time matches.
  • Resuming a session whose folder is gone (a discarded worktree, a deleted checkout) ran the agent in the dashboard's folder, where Claude refuses with "This conversation is from a different directory". The folder is recreated, empty, and the session resumes there.
  • Resuming a session that ran in an agent worktree after its window closed lost the worktree: no diff, merge or discard. The worktree is re-attached to the new window.
  • Resuming the same session twice at once (a double click, a phone retry) started two agents on one transcript; two launches at once on a stopped multiplexer failed with "duplicate session".
  • Codex and opencode windows in one folder, before the agent reported a session id, showed whichever session was newest. Each window now gets the first session that started after it opened.
  • Concurrent saves from the web dashboard, the terminal dashboard and the CLI could tear the session cache, so the next start re-read the whole history. Concurrent hook writes (parallel tool calls) could tear an agent's state record, and the watcher could drop the record of a window opened while it was polling.
  • Per-agent scopes failed, and the agent died at start, when the tmux server had been started without XDG_RUNTIME_DIR (from cron, or over ssh without a login session).

0.3.0 - 2026-10-04#

Bring in agents started elsewhere, and a browser terminal that survives sleep, backgrounding and flaky networks.

Fixed#

  • Agents launched by optimus from inside a Claude Code session inherited its session markers, so Claude Code treated them as child sessions and didn't save their transcripts.
  • Browser terminal could freeze or stay blank after a connection died silently (laptop sleep, phone in the background, a dropped network path). Terminals now send a heartbeat; the page reconnects after 40 s of silence, when it becomes visible again, or when the network comes back, and the server drops viewers whose browser is gone.
  • Late output from the previous agent could be painted into the terminal after switching agents.
  • After selecting an agent, keystrokes went to the page instead of the terminal (and could trigger shortcuts); the terminal now takes focus (desktop).

Added#

  • Agents running outside optimus: optimus finds Claude Code, Codex, opencode and other agents anywhere on the machine. Agents in your own tmux are linked in place (in the fleet, with live terminal, messages, answers and notifications); agents in a terminal tab can be taken over: stopped there and the same session resumed inside optimus (optimus takeover, T, browser button). Agents in containers are recognized as such.
  • A connection dot next to each agent's name in the browser: green live, yellow connecting, red lost (click to reconnect).

0.2.0 - 2026-10-03#

Run a fleet without babysitting it: agents tell you when they need you, you answer without attaching, parallel agents get their own worktrees, and context moves before quota runs out.

Added#

  • Reliable agent states from the agents themselves: Claude Code sessions get lifecycle hooks via --settings, Codex gets a notify program; needs input now shows the actual question ("wants to use Write: hello.txt").
  • Notifications when an agent needs input or finishes: desktop, multiplexer status line, browser, and optional phone push via ntfy (optimus watch, notifications.* config).
  • Answer an agent without attaching: ! in the terminal dashboard shows its question and forwards the next key; optimus answer <window> <key>.
  • One git worktree per agent (--worktree, -w, or the launch prompt), with changes shown per agent, and diff / merge / discard from the CLI (optimus wt), both dashboards and the API.
  • Fan-out: the same task to several agents, each in its own worktree (optimus fanout, F, browser), and optimus compare.
  • Preview and edit a handoff before it's sent (--edit, "✎ preview & edit first" in the TUI, "Preview & edit" in the browser).
  • Quota-aware handoff: when an agent's quota window passes handoff_suggest_pct (default 85%), optimus suggests continuing its running sessions in another agent (notification, C in the TUI, a banner in the browser).
  • Phone: optimus web --url prints a QR code of the login link (Tailscale addresses first); a 📱 button shows it in the dashboard.
  • The web dashboard is an installable app (PWA: manifest, icons, service worker) — Add to Home Screen over HTTPS, e.g. with tailscale serve.
  • Fleet summary everywhere: optimus fleet (--json, --tmux), appended to the Claude Code status line and shown in the multiplexer's status bar.
  • Automated sessions (claude -p, Agent SDK, codex exec, cron jobs) are detected and hidden from session lists by default (ls --all, z, browser checkbox); they still count in costs.
  • Full-text search inside transcripts: optimus search, S in the Sessions view, "inside transcripts" in the browser, with the matching passage.
  • Command palette: Ctrl-K / : in the terminal dashboard and Ctrl/Cmd-K in the browser — agents, recent sessions, launches per project and every action, matched by words in any order.
  • Inside your own tmux (3.2+), attaching opens the agent in a popup over your pane instead of nesting tmux (attach: auto, popup, nested).
  • Live cost per running agent (both dashboards, optimus ps) and a per-session budget (budgets.session_usd) with notifications at each multiple.
  • Jump to the next agent waiting for you: Alt-n anywhere in the multiplexer, i in the dashboards, optimus next.

Fixed#

  • Claude's workspace-trust dialog was shown as busy; it's now needs input.
  • optimus config set rejected the notifications.*, handoff_suggest_pct and attach keys documented in this release; a test now checks every documented key.

0.1.0 - 2026-10-03#

First public release.

Added#

  • Terminal dashboard (optimus) with Agents, Sessions, Projects and Usage views.
  • Agent multiplexer on a private tmux server: start, attach (Alt-q back), watch, broadcast, rename and stop agents; busy / needs-input / idle detection.
  • Session history, costs and transcripts for Claude Code (including sub-agents), Codex CLI and opencode; launch support for Gemini CLI, cursor-agent, aider, amp, crush, goose and a plain shell.
  • Context handoff between sessions and across agents: to a new agent, into a running one, to the clipboard or a file, optionally condensed by an agent.
  • Usage: daily/weekly/monthly spend, 5-hour blocks with burn rate, budgets, per model/agent/project breakdowns, and real 5h/7d quota for Claude (via optimus statusline) and Codex.
  • Browser dashboard (optimus web): live interactive terminals over websockets, message box with broadcast, phone-friendly key buttons, sessions, handoffs and usage; token auth.
  • Remote control by default: launching a session brings up the web dashboard; Claude sessions start with --remote-control.
  • One-step launch: optimus claude|codex|… [dir], optimus new with a default agent, N in the TUI, New session dialog on the web.
  • One-line installer with a setup wizard, release builds for Linux and macOS (amd64/arm64), CI on Linux and macOS.
  • Documentation site on GitHub Pages.

Fixed#

  • Agents not listed (and the web terminal returning 404) on tmux 3.3+, which escapes control characters in format output.