Unterm
v0.18 · signed + notarized · MIT · 4 platforms

The terminal that runs
every AI coding agent.

Install, sign in, configure, and launch Claude Code, Codex CLI, Gemini CLI, OpenCode, and Aider — one click each. Pick your vendor subscription or bring your own API key, per agent, per identity. And because Unterm exposes itself via MCP, the agent you just launched can drive Unterm back.

🔌 MCP-controllable Scriptable CLI 🖥️ Web Settings 🎬 Session recording 🪟 Split / focus from MCP 🔒 127.0.0.1 only

Unified AI agent launcher · Local-first · No cloud · No login

Unterm — alpha — /work/auth-service
MCP on
claude code
build
logs
agent-ready
claude: open /work/auth-service and switch cwd
unterm mcp.pane.set_cwd { pane_id: 7, cwd: "/work/auth-service" }
{ ok: true }
unterm mcp.exec.run { pane_id: 7, cmd: "cargo test" }
running 142 tests
test result: ok. 142 passed; 0 failed
unterm mcp.screen.read { pane_id: 7, lines: 5 }
"cwd switched, build is green"
claude: commit and open the release branch.
$
pwsh 7 | ~/work/auth-service | 120×32 | 📁 auth-service

What Unterm is, in 60 seconds

specs you can verify in source · refreshed each release
Latest version
v0.18 · 2026-05-20 · MIT
Bundled AI agents
5 signed manifests — Claude Code · Codex CLI · Gemini CLI · OpenCode · Aider. Ed25519-verified envelope from unterm.app/api/agents/manifests; per-agent auth mode picker.
Price
$0 forever · no paid tier · no subscription · no in-app purchase
Platforms
macOS (universal) · Linux x86_64 (.deb + AppImage) · Windows 10/11 (.msi + portable .zip)
Installer size
DMG 117 MB · .deb 35 MB · AppImage 46 MB · MSI 44 MB
Memory at idle
~110 MB resident · scales linearly with open panes
UI languages
9 — en · 简体 · 繁體 · 日本語 · 한국어 · Deutsch · Français · Italiano · हिन्दी
Control surfaces
MCP (JSON-RPC over TCP) · HTTP Web Settings · unterm-cli · GUI — same JSON state for all four
Agent integrations tested
Claude Code · Cursor · Codex CLI · custom Python / Node MCP clients — all via 1 socket, ~30 lines of code
Data collection
Zero telemetry · no account · no analytics · every server bound to 127.0.0.1
Tech stack
Rust · customized WezTerm engine · MCP (line-delimited JSON-RPC) · Tailwind + Alpine for Web Settings
v0.18 · AI Agent Launcher

Install every coding agent. One click each. No setup tax.

If you've ever tried to run more than one AI coding CLI side-by-side, you know the tax: npm install, OAuth flow, API key, ~/.config/<vendor>/<different format each>, env vars, profile separation. Unterm v0.18 collapses that into one settings tab + a CLI. No other terminal does this.

Claude Code
Anthropic
OAuth · BYO key · gateway
Codex CLI
OpenAI
ChatGPT OAuth · BYO key · gateway
Gemini CLI
Google
Google OAuth · BYO key · Vertex
OpenCode
SST
BYO key · local
Aider
Open-source
BYO key · local
01 · one click

Install in the GUI or via CLI

Click Install on any agent card, or run unterm-cli agent install <id>. Unterm runs the right command for your platform (npm / pipx / etc.), verifies the binary lands on PATH, and re-detects automatically.

02 · subscription-safe

Subscription by default. BYO key opt-in.

Most agents ship with OAuth tied to a paid subscription (Claude Pro, ChatGPT Plus, Google AI Pro). Unterm defaults to that mode — no API key is ever silently injected. Switch to bring your own key or custom endpoint explicitly in the Configure form when you actually want per-token billing or a corporate gateway.

03 · signed catalog

Ed25519-signed manifest catalog

The list of agents + their install commands isn't hard-coded into Unterm — it's a signed envelope served from unterm.app/api/agents/manifests. A compromise of the CDN can't push curl | sh to your machine; the public key is baked into every Unterm binary.

AI controls the terminal. MCP makes it real.

Most terminals embed AI inside the binary. Unterm does the opposite: keep AI outside, expose the terminal as a surface that any external agent can grip via MCP. The terminal is the thing being controlled; the agent is the thing doing the work.

Typical case

One AI controls another AI through the terminal.

The outer agent owns the terminal session. It switches cwd, launches an inner coding agent in a pane, reads the logs, and keeps iterating until the repository is green.

01
Open the repo

The outer agent points the active pane at the project root so every command, log, and screenshot stays anchored to the same working directory.

02
Start the inner agent

It spawns a coding agent in a split pane, gives it the task, and lets that agent do the edit loop inside the terminal.

03
Read, retry, release

The outer agent reads test output and pane state, retries when needed, and only moves to commit or release when the terminal says the work is done.

outer agent → inner agent
demo
open /work/auth-service and start a worker pane
unterm mcp.pane.set_cwd { pane_id: 7, cwd: "/work/auth-service" }
{ ok: true }
unterm mcp.exec.run { pane_id: 7, cmd: "claude code" }
inner agent ready
unterm mcp.exec.run { pane_id: 7, cmd: "cargo test" }
running 142 tests
test result: ok. 142 passed; 0 failed
unterm mcp.screen.read { pane_id: 7, lines: 5 }
"build is green, commit the fix"
$
pane: 7 | cwd: /work/auth-service | worker: claude code | tests: green
Live snippet · same socket, both directions

The terminal AI agents drive — including their own.

Below is a real session from this Unterm window. Claude Code, running in pane #0, called session.split over MCP to put pane #5 on the right half, session.focus to make it active, then typed commands into it character-by-character with session.input. Same TCP socket reads what the shell echoed back via screen.text. No special agent integration — vanilla JSON-RPC, ~30 lines of Python.

claude_drives_pane.py
# Claude Code, running in pane 0 of this very Unterm window.
# Tells its own MCP server to spawn a new tab, then types into it.

import socket, json, time

s = socket.create_connection(("127.0.0.1", 19876))

# 1. auth — token is in ~/.unterm/instances/<name>.json
s.sendall(b'{"jsonrpc":"2.0","id":1,"method":"auth.login",'
          b'"params":{"token":"…"}}\n')

# 2. split CURRENT pane right-half (since v0.17) · also `agent.launch` (v0.18) — true side-by-side, not a new tab
s.sendall(b'{"jsonrpc":"2.0","id":2,"method":"session.split",'
          b'"params":{"id":0,"direction":"right","cwd":"/path/to/repo"}}\n')
new_pane_id = …  # parse response → e.g. 5

# 3. focus it so the user sees the new pane immediately
s.sendall(b'{"jsonrpc":"2.0","id":3,"method":"session.focus",'
          b'"params":{"id":new_pane_id}}\n')

# 4. type, character by character, with human rhythm
for ch in "git log --oneline -5\n":
    payload = json.dumps({
        "jsonrpc": "2.0", "id": 4,
        "method": "session.input",
        "params": {"id": new_pane_id, "input": ch}
    })
    s.sendall((payload + "\n").encode())
    time.sleep(0.03)

# 5. read what the shell echoed back — same socket, opposite direction
# s.sendall(... method "screen.text", params {"id": new_pane_id})
pane #5 — driven by pane #0
alexlee@192 unterm % # 👋 Claude 通过 MCP 实时打字进来 ↓
alexlee@192 unterm % pwd
/Volumes/Dev/code/unterm
alexlee@192 unterm % git log --oneline -5
5f44d15 (HEAD -> master, tag: v0.18) release: prep v0.18 — AI agent integration
8ae3786 agents tab: fix detail view (route + detect plumbing)
7c18235 agents tab: wrap detail view in x-if so child bindings only run when open
6ff27a9 AI agents: Web Settings tab + 'Shell → AI Agents' submenu
6d22e2f AI agent integration: signed manifests + install/auth/configure/launch runtime
alexlee@192 unterm % echo '↑ 5 个 commit 都是 Claude 用 unterm-cli + MCP 推的'
↑ 5 个 commit 都是 Claude 用 unterm-cli + MCP 推的
alexlee@192 unterm % ls -la web/src/pages/docs/ | head -10
total 368
drwxr-xr-x 9 alexlee staff   288  agent-integration.md
drwxr-xr-x 6 alexlee staff   192  architecture.md
-rw-r--r-- 1 alexlee staff 14433  cli-reference.md
-rw-r--r-- 1 alexlee staff 22051  configuration.md
-rw-r--r-- 1 alexlee staff 25587  mcp-reference.md
-rw-r--r-- 1 alexlee staff 39507  multi-instance.md
-rw-r--r-- 1 alexlee staff 23827  profiles.md
alexlee@192 unterm % 

The agent that wrote this section ran exactly that snippet, then used screen.text to copy the right-hand output back into this HTML. The v0.18 tag visible above? Same agent pushed it 30 minutes ago. Read AND write on the same socket — that's the whole story.

Three ways to use Unterm

We didn't build for one workflow. The MCP surface means each persona gets the same control plane through different entry points.

🤖
AI engineers

Drive multiple terminal panes from Claude Code, Cursor, or your own agent. Each pane is one task; your agent picks where to type. Multi-instance NATO names (alpha, bravo, charlie…) make routing across windows trivial.

  • Director / worker pattern: outer agent supervises inner agent in a pane
  • Long-running watcher: kick off a build, poll until idle, decide next step
  • Multi-pane orchestration: fan work across projects, aggregate results
  • Recording with token redaction for review and fine-tune
⚙️
DevOps & SREs

Cron-friendly CLI for everything you can do in the GUI. unterm-cli ships in every release; pipe --json through anywhere downstream that wants raw JSON-RPC. Same surface for ops scripts, dashboards, runbooks.

  • Auto proxy detection: macOS scutil / Windows registry / GNOME gsettings
  • Headless screenshots and pane reads for incident docs
  • Recording → markdown for runbook generation, PII-redacted by default
  • No telemetry, no login, every server bound to 127.0.0.1
🔧
Power users & OSS hackers

MIT-licensed WezTerm fork with first-class agent integration. Patches accepted on GitHub. Build it yourself; the binary CLI ships in every release. Web Settings UI is a Tailwind + Alpine SPA — fork the page, change the colors.

  • Universal arm64 + x86_64 macOS binary, signed with Developer ID
  • Linux .deb (apt) and AppImage (any distro)
  • Windows MSI with WiX 6 + portable .zip
  • 9 locales out of the box, system locale auto-detect

Download by platform

Pick the signed bundle for your OS. The direct links below go straight to GitHub Releases.

curl -fsSL https://unterm.app/install.sh | sh

Detects OS + arch, downloads the right artifact for the latest release. macOS gets the signed + notarized DMG into /Applications. Linux uses apt when available, falls back to the AppImage in ~/.local/bin.

Or grab the artifact directly:

🍎
117 MB
macOS
Universal arm64 + x86_64 .dmg, signed + notarized.
Unterm-macos.dmg →
🐧
35 / 46 MB
Linux
.deb (Debian/Ubuntu) and AppImage (any distro), x86_64.
🪟
44 / 64 MB
Windows
.msi installer or portable .zip, x64.

Four control surfaces, one engine

Every Unterm window starts a local MCP server and an HTTP settings server. Read and write the same JSON state from any of them.

🔌
MCP server

Line-delimited JSON-RPC on 127.0.0.1:19876, auth-token gated. Spawn shells, read pane state, capture screenshots, control sessions.

unterm-cli

Same surface from any shell, cron job, or script. Thin JSON-RPC client over the local MCP — no duplicated business logic.

🖥️
Web Settings

Modern config UI in the browser, not the cell grid. Tailwind + Alpine SPA at 127.0.0.1:19877. Themes, proxy, recordings, language.

🌍
9 languages

en / 简体 / 繁體 / 日本語 / 한국어 / Deutsch / Français / Italiano / हिन्दी out of the box. System locale auto-detect.

🎬
Session recording

OSC 133 block-segmented markdown with built-in redaction. Recordings live in <cwd>/.unterm/sessions/.

📸
Region screenshots

One-click region capture from the status bar. PNG to disk, image to clipboard, path to text clipboard.

🌐
Auto proxy detect

Reads macOS scutil / Windows registry / GNOME gsettings / env. One-toggle on/off. No URL config.

⚙️
GPU rendering

Built on a customized WezTerm engine — Metal on macOS, OpenGL on Linux, DirectX via ANGLE on Windows.

Where Unterm stands out

Three claims you can grep, build, or run yourself. No marketing fog.

🤖 v0.18
The terminal you boot every AI coding CLI from

v0.18 makes Unterm a one-click launcher for Claude Code, Codex CLI, Gemini CLI, OpenCode, and Aider. Each agent's install command, OAuth flow, API key, and native config file are described by a signed manifest fetched from unterm.app; the runtime drops the key into your OS keychain, writes the agent's own JSON/TOML/YAML config (preserving unknown fields), exposes Unterm itself to the agent as an MCP server, and records the session into audit — all reachable from the CLI and the new AI Agents Web Settings tab.

🪟 v0.17
AI splits panes from outside the terminal

session.split + session.focus over MCP let an external agent (Claude Code, Cursor, your script) carve the active window left / right / up / down and hand focus to the new pane — without simulating any keystroke. Built into the Python snippet on the hero. No other terminal exposes pane geometry to outside processes this way.

👁️ v0.16
Every agent write is auditable, revocable, reviewable

Each session.input / exec.send is logged with the calling agent's identity. First write from a new agent triggers an Allow / Block / Always-allow banner. Trust persists to ~/.unterm/trusted_agents.json and is one click revocable from the Web Settings MCP tab. The status bar shows live MCP write count.

Quality-of-life

Small touches that add up

Daily-driver polish — none are headline features, but together they remove friction.

👻
Cross-pane ghost text

Fish-style grey prediction continues your input from any pane's shell history; or End accepts.

session.suggest bar

Agents propose commands without touching the PTY — sit above the status bar; Tab accepts, Alt+Enter accept-and-run.

📋
Region screenshot → clipboard

Drag-select any rectangle from the status bar; PNG to disk, image to clipboard, file path as text — all at once.

🎨
Theme + per-tab CWD

9 bundled themes; unterm-cli theme set midnight changes them all live. Status bar shows active pane's $HOME-relative cwd.

📁
Native right-click on macOS

Finder right-click → Open in Unterm. Uses the AppleScript Services extension — no in-app context menu chrome.

🪪
Identity chip in status bar

Active identity profile (GitHub PAT / AWS keys / npm token bound to this window) shows in the status bar; click to spawn the next profile.

🚦
Zero-config proxy

Reads macOS scutil / Windows registry / GNOME gsettings / env. One toggle on/off. No URL pasting.

🌐
OSC 133 block segmentation

Recordings split on shell prompt boundaries automatically. Each block has its command, output, exit code, duration — searchable.

What's new in v0.18

Reflexive control closes the loop: agents can split + focus panes from MCP without simulating keystrokes, and a new MCP tab in Web Settings makes trust persistent + revocable. Builds on the v0.16 audit + suggest foundation.

v0.18 AI Agent integration: 5 first-party CLIs, one click each

Install / authenticate / configure / launch any of Claude Code, Codex CLI, Gemini CLI, OpenCode, or Aider directly from Unterm's Web Settings or `unterm-cli agent ...`. Each agent is described by a signed manifest (Ed25519, served from unterm.app/api/agents/manifests, with a baked fallback so offline installs still work). Settings are schema-driven: edit them in a typed form and Unterm writes the agent's native config file with `preserve_unknown_keys` semantics; API keys land in the OS keychain via the existing identity profile. New Shell → AI Agents menu spawns each one in a fresh tab with the right env injected. Every launched session lands in the audit index tagged agent_id / manifest_version / profile.

v0.17 session.split + session.focus + an MCP trust panel

Three pieces that close the loop on "AI drives the terminal — including its own." session.split lets an agent split a pane left/right/up/down without simulating a keystroke; session.focus makes the new pane active so the hand-off is visible to the user. Both are exercised in the live snippet above. Web Settings gains a new MCP tab: a runtime trust list (with per-agent write counts and one-click revoke) plus the last 80 audited write attempts in a sortable table. Trust persists to ~/.unterm/trusted_agents.json so Alt+A survives a restart. New /docs/agent-recipes page collects 9 copy-pastable Python snippets.

v0.16 Agent-aware terminal — audit, suggest, ghost text

Three pieces fall into place to make Unterm a real AI-collaboration terminal. (1) Every session.input / exec.send is audited; the first time a new agent writes to a pane, a blocking banner asks the user — [Enter] allow, [Esc] block, [Alt+A] always-allow. The new mcp:N chip in the status bar tracks cumulative MCP PTY writes; click to copy the audit log. (2) session.suggest lets agents propose text without ever touching the PTY directly — a ✨ suggest bar sits above the status bar, [Tab] accepts, [Esc] dismisses, [Alt+Enter] accepts and runs. (3) Fish-style grey ghost text continues your input from cross-pane shell history; [→] / [End] accepts the prediction. All three keystrokes (Tab, Esc, Enter) pass through to the shell when no banner / suggestion / prediction is showing — vim, less, fzf all keep working unchanged.

v0.15 Config resilience — unknown fields no longer crash

Setting an unrecognized key in your unterm.lua (e.g. a future or experimental option) used to abort the process on Windows release builds. The Lua FFI callback crossed a panic = abort boundary and triggered an unrecoverable crash with no diagnostic. v0.15 defaults config_builder() to non-strict mode: unknown fields produce a visible warning and the app continues to start normally.

View all releases on GitHub →

Six principles, no exceptions

01
Local-first, no cloud

Every server, every API endpoint, every recording lives on 127.0.0.1. No login, no telemetry, no subscription. Your shell history is yours.

02
AI lives outside the terminal

No chat overlay, no ghost-text autocomplete, no inline AI panel. The terminal is the surface — Claude Code, Cursor, your scripts grip it through MCP.

03
MCP is a first-class surface

Every product feature ships with an MCP method and a CLI subcommand on day one. If it can't be driven from outside, it doesn't ship.

04
Cross-platform parity is correctness

A feature that works on Windows but bails on macOS or Linux is a bug, not a 'not yet supported.' Mac, Linux, Windows ship together.

05
Subtraction over decoration

When a feature belongs to the OS, use the OS. No in-terminal custom right-click chrome, no Cmd+Q confirmation, no manual proxy URL config — Finder integration now uses the native right-click extension and Services.

06
Respect the subscription. Default OAuth.

When you install an AI agent through Unterm, the default authentication mode is the vendor's official subscription (OAuth) — your Pro / Plus / Team plan. We never silently inject an API key into a session; per-token billing happens only if you explicitly switch the auth mode to 'bring your own API key' or 'custom endpoint' in the Configure form. This is an opt-in, not a footgun.

How Unterm differs

Three terminals reset the bar in 2026. They each picked a different lane.

Feature Unterm Warp iTerm2 Ghostty
MCP-controllable from outside
Local-first, no cloud
GPU rendering
macOS + Linux + Windows macOS macOS+Linux
Open-source client ✓ MIT AGPL ✓ GPL ✓ MIT
AI inside the terminal ✗ (by design) ✓ (cloud)
9-language native UI en en en

Comparison reflects publicly documented features as of 2026-05-01. Other terminals may have closed-source or roadmap items not listed.

Get Unterm 0.17

macOS bundle is signed with a Developer ID and Apple-notarized. Linux .deb / AppImage and Windows .msi / .zip are also published.

Open the v0.18 release

Frequently asked

What is Unterm?

A cross-platform terminal emulator with built-in MCP, HTTP, and CLI control surfaces. The product thesis: terminal as MCP-controllable surface, so any external AI agent can drive it from outside instead of having an AI baked into the terminal itself.

How does it work with Claude Code, Cursor, or other agents?

Each Unterm window starts a local MCP server (TCP, JSON-RPC, auth-token gated). Point your MCP client at 127.0.0.1:<port> — the port + token are written to ~/.unterm/server.json on launch. The agent can spawn shells, run commands, read pane state, capture screenshots, toggle recording, and switch settings.

How do I drive multiple Unterm windows from one agent?

Each Unterm process is one instance with a NATO-phonetic name (alpha, bravo, …) recorded in ~/.unterm/instances/<name>.json. Call instance.list on any one of them to enumerate; pick by cwd / title / start order; connect to that instance's port with its auth token. ~/.unterm/active.json points at the most recent live instance for single-instance fallbacks.

How is this different from Warp?

Warp embeds AI inside a closed cloud orchestrator (Oz) — external tools like Claude Code can't drive Warp from outside. Unterm picks the third lane: keep AI out of the terminal, expose the terminal itself as an MCP-controllable surface, and let any agent grip it. No cloud, no login.

Where does my data go?

Nowhere external. MCP and Web Settings servers bind to 127.0.0.1 only. Session recordings land under <project>/.unterm/sessions/ with built-in redaction for tokens. There is no telemetry, no analytics, no login, no cloud round-trip. Your shell history is yours.

Does Unterm phone home, even once?

No. Zero telemetry by default — not even an opt-in dialog. The only outbound HTTP requests Unterm makes are: (1) at user request, when you click a download link in Web Settings; (2) by your shell, like normal — anything your terminal would do, it still does. We don't ship analytics, error reporting, install pings, or update checks.

Is there a paid tier or premium feature?

No. Unterm is MIT-licensed; the same single binary ships every feature. No subscription, no Pro tier, no plugin marketplace, no "buy now to unlock split panes." If you'd like to support the project, the Sponsor section above is the only ask.

How big is the install and runtime?

macOS DMG ~117 MB · Linux .deb 35 MB · AppImage 46 MB · Windows MSI 44 MB. At idle with one window open, resident memory is ~110 MB; scales linearly per pane. Built on a customized WezTerm engine (GPU rendering: Metal / OpenGL / DirectX) — the binary is bigger than a barebones terminal but the runtime cost is dominated by your shell, not the renderer.

Does Unterm detect my system language?

Yes. On first launch, Unterm reads the OS locale (defaults on macOS, $LANG on Linux, registry on Windows) and picks the closest of 9 bundled UI languages. You can override per window in Web Settings → Language. Translations live in wezterm-gui/src/i18n/locales/*.json — patches welcome.

What stops a rogue agent from running rm -rf on my repo?

Three gates: (1) MCP server only listens on 127.0.0.1 — no network access. (2) Auth-token gated; the token is in ~/.unterm/instances/<name>.json, an agent without read access to that file can't even connect. (3) First write from a new agent triggers a blocking Allow / Block / Always-allow banner; the audit log records every write attempt with calling agent's identity. You can revoke trust at any time from the Web Settings MCP tab.

How do I script it?

Use unterm-cli: session list, proxy status, theme set midnight, session record start, screenshot. Pass --json to any subcommand for raw JSON-RPC output suitable for shell pipelines and cron jobs.

Which platforms ship signed and notarized?

macOS: universal arm64 + x86_64 DMG signed with a Developer ID and Apple-notarized + stapled (no Gatekeeper warnings). Linux: .deb for Debian/Ubuntu and AppImage for any distro. Windows: WiX-built MSI installer and portable .zip. All published to GitHub Releases on every minor tag.

Is it open-source?

Yes — MIT licensed. Built on top of the WezTerm engine for renderer / font / SSH / mux work, with a thin Unterm product layer (MCP, Web Settings, recording, i18n, signing pipeline) on top. Source at github.com/unzooai/unterm.

How do I contribute?

Open an issue or PR on GitHub. The project tracks bugs, feature requests, and discussion in one queue. We bundle accumulated fixes into minor releases — patch-level versions don't trigger CI builds. Documentation lives in-repo at /docs.