* fix(host): save local files atomically via a temp file and rename LocalHost::write_file truncated the target in place, so a crash, a full disk or a killed process mid-save destroyed the user's file. It now writes a hidden sibling temp file, syncs it, keeps the old file's mode and renames it over the target, removing the temp file on any error. It still writes in place where a rename would change something visible: a non-regular target (symlink, directory, FIFO), a read-only file, and on Unix a hard-linked file or one owned by another user, or when the temp file cannot be created (e.g. a read-only directory). * feat(editor): add editor_text for encodings, line endings, indentation and EditorConfig A pure module the code editor will use when loading and saving files: decode detects BOMs, binary files, UTF-8, GB18030 and a lossless Windows-1252 fallback and normalises CRLF; encode restores the exact bytes and names the first unrepresentable character; detect_indent infers tabs or a 2/4/8 space width with language defaults; and editorconfig_for resolves .editorconfig sections with save-time rules. * feat(editor): share buffers across tabs, guard unsaved work, add a file strip - One buffer per file per window; tabs list which buffers they show. The same file open in two tabs is no longer two diverging copies. - Closing a tab, its last pane, the window, or quitting asks about unsaved files (Save / Cancel / Discard) instead of dropping them. Bulk closes skip tabs with unsaved files; a tab that vanishes any other way hands its unsaved buffers to the tab in front. - File tree rename/delete now retarget or flag the open buffer, so a save no longer recreates the old path. - Saves check the file's mtime first and ask before overwriting a change made elsewhere; this is the only detection SFTP buffers get. - Dirty is a comparison with the saved text, so undoing back clears it. - Reloads replace only the changed span as an ordinary edit, keeping undo. - Load/save go through editor_text: encoding, BOM and CRLF round-trip, indentation is detected, .editorconfig is honoured. - Header shows a strip of open files; New File, Save As (native panel locally, a path bar remotely), Go to Line (Ctrl+G), and the status bar shows indentation, encoding and a clickable line ending. - Open files are remembered per tab across restarts. * feat(search): quick open a file by name from a Files tab Search Everywhere gains a Files tab that finds any file in the active tab's project by fuzzy name and opens it in the built-in editor, with `name:line[:col]` jumping to that spot. The list comes from one walk of the project through the host (Host::search with an empty query), so it works the same on local, SSH and WSL workspaces and skips what the tree hides: dotfiles, .git and gitignored paths. The walk is capped at 50k entries / 20k directories, kept between openings and revalidated in the background each time the search opens. Files join the All tab once a query finds them. Go to File... is bound to Cmd+O on macOS (Cmd+P is already Search Everywhere) and ships unbound elsewhere, where every obvious chord is taken or owed to the shell. * chore(editor): allowlist the editor session file, tidy lints * fix(editor): keep restored file order, drop stale close waits, carry files through tab merges - Background arrivals (restore, merge, rescue) append to the strip in order instead of inserting beside the active file, which reversed them. - A cancelled Save As, a dismissed path bar, or a dropped buffer cancels any close that was waiting on that save. - Merging a tab into another carries its open files along. - A shell exiting closes its tab without a prompt it could not honour; unsaved buffers move to the tab in front. - Tabs rebuilt under the same id (server restart) restore their files. * fix(host): only fall back to an in-place write when the rename is refused On Windows every failure of the atomic save fell back to fs::write, including a failure while staging the temp file. A full disk would then truncate the original in place, the very loss the temp file prevents. Staging errors now return as-is; only a refused rename (a file held open elsewhere) takes the in-place path.
tty7
A terminal workbench: persistent sessions, remote work, agents.
Pure Rust · GPU rendering on Zed's gpui · VT core from Alacritty
English · 简体中文
Why
A background server owns your shells and panes — not the window. Everything below follows from that.
- Performance — ~2× the throughput of Alacritty, Ghostty, or Kitty (benchmarks)
- Persistent sessions — quit or reboot; your shells and supported agent sessions keep running, no tmux
- Agent-aware — Claude Code, Codex & co.: status, notifications, and git context for every repo at once
- Scriptable by agents — one agent opens a pane for another, hands off a task, waits, and reads the result, with or without the GUI running
- Editor-grade input — suggestions, completion, highlighting, history search, with no plugin to install
- Remote development — files, repos, panes, and git data stay on the remote machine, over a native SSH stack
Install
Native builds for macOS, Windows, and Linux on Releases:
| macOS | …-macos-arm64.dmg · …-x86_64.dmg |
drag into Applications |
| Windows | …-setup.exe · portable ….zip |
|
| Linux | …-x86_64.AppImage |
chmod +x and run — X11/Wayland libraries bundled |
What's inside
| Agent-aware | per-pane detection (25 CLIs) · status dot · notifications · branch + diff · tray icon when input is needed · resume after reboot · tab sidebar grouped by repository, with pinned groups |
| CLI + Skills | bundled tty7 CLI · agent skill · run streams a command and exits with its code · split · send · wait --until free · capture |
| Editor-grade input | ghost suggestions from history · explained tab completion · syntax highlighting · multi-line editing · click places the caret · ⌃ R fuzzy history |
| Window | tabs & splits · ⌘ P Search Everywhere · ⌘ F scrollback search · ⌘ J panel with process tree and listening ports · 13 themes, your own YAML, iTerm2 import · IME |
| Shell integration | injected when a pane starts, nothing to install · prompt marks · working directory · exit codes · command-finished notifications · zsh, bash, fish, PowerShell, WSL, remote panes |
| Remote workspaces | remote files, repos, changes, diffs, worktrees, tabs, and panes · reconnect from any client and continue where you left off |
| SSH | native russh stack: profiles with keychain secrets · SFTP panel · port forwarding · jump hosts · one-time, unprivileged tty7-server install |
Supported agents
Detection is free: brand avatar, branch + diff, tab title.
Status takes one click under Settings → Integrations to install that agent's hook,
and brings the status dot, notifications, the tray icon, tty7 wait, and resume
after a reboot. Fork needs both — the agent's own fork command, and the hook
that tells tty7 which session to fork.
The full support matrix, all twenty-five
| Agent | Detected | Status · resume | Fork |
|---|---|---|---|
| Claude Code | ✓ | ✓ | ✓ |
| Codex | ✓ | ✓ | ✓ |
| TraeCode | ✓ | ✓ | ✓ |
| Grok | ✓ | ✓ | ✓ |
| OpenCode | ✓ | ✓ | ✓ |
| Oh My Pi | ✓ | ✓ | ✓ |
| Prime Agent | ✓ | ✓ | ✓ |
| Droid | ✓ | ✓ | ✓ |
| Qwen Code | ✓ | ✓ | ✓ |
| Goose | ✓ | ✓ | ✓ |
| Qoder CLI | ✓ | ✓ | ✓ |
| CodeBuddy | ✓ | ✓ | ✓ |
| Gemini | ✓ | ✓ | |
| Copilot | ✓ | ✓ | |
| Kimi Code | ✓ | ✓ | |
| Pi | ✓ | ✓ | |
| Crush | ✓ | ✓ | |
| Antigravity | ✓ | ✓ | |
| Cursor | ✓ | ✓ | |
| Aider | ✓ | ||
| Amp | ✓ | ||
| Auggie | ✓ | ||
| Hermes | ✓ | ||
| Vibe | ✓ | ||
| Empryo | ✓ |
None of them are wrapped or proxied — the agent you start is the agent you get,
in a normal PTY, with its own interface. An agent launched through a wrapper
script can be mapped to one by name with agent_commands in config.json.
Every agent on your PATH is also a row in Search Everywhere (Agent: Claude Code, …)
that opens it in a new tab; agent_launch sets the command line it starts with.
Documentation
Full documentation lives in docs/ —
keyboard shortcuts ·
config.json ·
CLI reference. The agent-facing CLI interface is also
documented in skills/tty7/SKILL.md.
Install the skill with:
npx skills add l0ng-ai/tty7 # install
npx skills update tty7 # update later
Benchmarks
Same machine, same day, same 155×40 grid — Apple M1 Pro, macOS 26.3.1, five-run averages (2026-07-04):
| tty7 | Alacritty | Ghostty | Kitty | |
|---|---|---|---|---|
Plaintext I/O — 11 MB cat (lower = better) |
95 ms | 239 ms | 179 ms | 185 ms |
| DOOM-fire frame rate (higher = better) | 888 fps | 485 fps | 552 fps | 617 fps |
| Cold-launch memory | 116 MB¹ | 105 MB | 128 MB | 130 MB |
¹ GUI 105 MB + the persistent server 11 MB.
Methodology and one-command reproduction: scripts/bench/.
Built on gpui and alacritty_terminal · Apache-2.0 · Discord · Changelog
