Anthropic killed Conductor.build's subscription pricing, so I built an open-source replacement in a weekend
Termic (termic.dev) is a native macOS app that spawns the real Claude Code, Codex, and Gemini CLIs in PTYs. Subscription stays valid, per-workspace sandbox, multi-repo workspaces. Rust, Tauri 2, React, no Electron, AGPL.
Just got used to Conductor.build. Muscle memory finally there, parallel agents across worktrees, the whole flow clicked. Then Anthropic changed how the Claude Agent SDK is billed on a Claude plan: third-party harnesses (Conductor is exactly that) now draw from a $100/month API-credit pool instead of the subscription itself. That pool gets eaten in less than a day of real coding agent use. Effectively it stopped working on the plan I already pay for.
So I spent the weekend (and a long Monday night) building a replacement. It’s called Termic, it’s open source: termic.dev / github.com/simion/termic.
TL;DR. Termic spawns the real claude / codex / gemini CLIs in PTYs instead of wrapping the SDK. Your subscription stays valid. Per-workspace macOS sandbox (filesystem + network). Multi-repo workspaces with auto-allocated sibling ports. Bring your own agent in 30 seconds.
Why running the real CLIs
The SDK was the dependency that just broke for everyone. So I removed it.
Termic runs the official claude, codex, gemini binaries the same way iTerm runs them. PTY in, bytes out. No vendor-wrapped client, no version mismatch, no broken auth flow because some third party hasn’t updated their adapter yet.
Two things fall out of this:
- Subscription stays valid. The CLI is the official one, the auth is the official one, billing is whatever the vendor decided for first-party use.
- Whatever ships next in any of those CLIs (new flags, plan mode, model upgrades) lands in Termic the same day. There’s nothing to update on my side.
Pain points I addressed
Things that bit me daily in Conductor.
Worktree or repo-root, your choice
Conductor forces a git worktree every time. Most of the time that’s the right call: parallel agents on parallel branches is the killer feature. But sometimes I just want the agent to work on main directly without a worktree dance. Termic lets you pick per workspace.
Sandbox (filesystem + network)
This is the one I’m proudest of. The one I needed the most.
Every workspace can be sandboxed. macOS Seatbelt for the filesystem, an in-process CONNECT proxy with a per-CLI hostname allowlist for the network. With sandbox on, the agent gets read/write access only to the worktree directory and the agent’s own config dirs. Everything else — your home dir, credentials, browser data — is inaccessible by default unless you explicitly add it to the allowlist.
Network works the same way: the agent can only reach hosts on the allowlist. Defaults cover Anthropic / Google / OpenAI, GitHub, npm/pip/cargo. Add more per project.
The sandbox is pinned at workspace creation. There’s no “toggle off” mid-session. If you want to flip it, archive the workspace and create a new one. That’s the security boundary: the agent can’t talk its way out of the cage it was spawned in.
While testing this I noticed something. Claude Code attempts reads on ~/.config/gh/hosts.yml (GitHub auth tokens) and ~/Library/Application Support/{Chrome,Brave,Arc} (browser profile dirs) on idle. The sandbox blocked them. Without it those reads would have succeeded silently.

I’m reproducing the read-vs-stat distinction before writing that up properly. Either way, this is the reason the sandbox exists.
Multi-repo workspaces
A lot of features span multiple repos. Frontend in one, backend in another, sometimes infra in a third. Conductor makes you switch projects and lose context. Termic has a “multi-repo project” type: pick N member repos, get a wrapper directory with shared CLAUDE.md, and every workspace under it gets all members worktreed (or symlinked) into one dir.

Each member gets its own $TERMIC_PORT so parallel dev servers don’t collide. Sibling ports are exposed as $TERMIC_PORT_<MEMBER>. My frontend’s actual run script:
PORT=$TERMIC_PORT \
NUXT_API_READ_BASE_URL=http://localhost:$TERMIC_PORT_PYDPF \
NUXT_API_WRITE_BASE_URL=http://localhost:$TERMIC_PORT_PYDPF \
just run
One diff view aggregates changes across all members. One archive cleanly tears all worktrees down.
Bring your own agent
Settings → Agents. Add any PTY-based CLI in 30 seconds. OpenCode, aider, Ollama, custom shell scripts. The built-in three (claude / gemini / codex) you can also edit to point at a wrapper script, a different binary, whatever.

Same future-proofing as running the real CLIs: whichever agent gets popular next is a one-minute add, not a feature request.
How I detect “agent is done”
This part took embarrassingly long to get right.
My first attempt: watch the PTY output cadence. If no bytes for N seconds, the agent must be done. Wrong about half the time. Long tool calls, slow API responses, all triggered false positives. Users would click into a workspace expecting “done” and find the agent mid-thought.
Then I realized the agents already tell the terminal exactly when they’re working. iTerm shows a spinner because the agent sends a sequence asking for one. Termic just needs to listen.
- Claude Code emits
OSC 9;4, the ConEmu/iTerm progress protocol. State 3 = busy, state 0 = idle. - Gemini sets the OSC 0 window title with explicit strings:
◇ Readywhen idle,✦ Working…while thinking,✋ Action Requiredwhen waiting on you. - Codex does the same with literal words:
Working/Thinking/Ready/Waiting/Action Required.
Termic classifies these and surfaces two tab-level icons: green check (turn complete), yellow bell (agent is blocked waiting on your input). Plus a desktop notification. Click the notification, you jump straight to that workspace and tab.
Switching to the sender-emitted signals dropped false positives effectively to zero. The lesson: when the protocol exists, use the protocol. Don’t pattern-match output like an animal.
Stack
Rust for the backend (PTY management, sandbox provisioning, git, IPC). Tauri 2 for the desktop shell, system WebView (WKWebView on macOS), not Electron, bundle around 15 MB. React 19, Vite, TypeScript on top. xterm.js + WebGL for terminals. CodeMirror 6 for the editor and the side-by-side diff. portable-pty (wezterm’s fork) for PTY handling.
Cold start under 400ms on M-series.
What’s next
Linux and Windows builds once I free up enough disk to spin up the VMs. Tauri makes this mostly a CI exercise but I keep procrastinating it.
Apple Developer signing. Right now you install via Homebrew because I haven’t expensed the $99/year yet:
brew install simion/termic/termic
Smarter sandbox auto-allow so first-launch with weird tooling (poetry, devbox, nix) is one-click.
Site: termic.dev. Code: github.com/simion/termic. AGPL-3.0. Issues and PRs welcome.