tty7
A pure Rust terminal whose shells belong to a background server rather than to the window: quitting the app leaves them running, a restart brings the panes back with their layout and the last of what was on screen, four CLI commands let one coding agent drive another, and a remote workspace is that same server running on another machine.

What it is
A terminal written in Rust that keeps its shells in a background server instead of the window. Quit the app and every shell keeps running; after a restart the panes return with their layout and the last of what was on screen, and supported coding agents resume the conversation they were in. Twenty-six coding CLIs are recognised by the command running in a pane and listed in one sidebar as working, waiting or done, a status that arrives through a hook installed into the agent’s own configuration. Because that status is something a program can ask for, an agent can ask it: split, send, wait and capture are the whole loop, and they work with the window closed. A remote workspace is the same server on another machine — tabs, panes, git and diffs stay over there and nothing is synced — reached through an SSH client the project wrote itself. Rendering is GPU-side on Zed’s gpui, the terminal core comes from Alacritty, and builds ship for macOS, Windows, Linux, iOS and Android.
Who built itThe account that owns the repository and wrote 1,302 of its 1,546 commits in twelve weeks; the other 244 come from thirty-three accounts, one with 89 commits and one with 30. Of the 316 commits carrying a co-author trailer, 92 name a Claude model. The report carries no profile data beyond the commit history.
How it is put together
The parts · 6A client and a server. A daemon owns the panes, their PTYs and their scrollback, while the window, the command line and the phone are all clients of it — which is why quitting a client kills nothing, and why a remote workspace needs no separate feature, since it is the same daemon somewhere else. Three consequences shape the code. The daemon must survive being replaced, so there is a handoff path, a pidfile, a singleton guard, an update guard and a separate updater binary. The daemon is the source of truth for what exists, so workspaces, panes and recently closed tabs are records in a machine tree that every client reads rather than state held by one window. And the line between the local and the remote host is a real interface, with a conformance test and a CI script that checks nobody crossed it. Rendering is GPU-side through gpui on a fork of Zed, with the VT core taken from Alacritty.
- crates/tty7-core/src/daemon/
- The server:
server.rsat 68 KB,control.rsat 110 KB,pane.rsat 316 KB,spawn.rsat 94 KB,protocol.rsat 104 KB androuter.rsat 52 KB, surrounded by what a long-lived process needs —singleton.rs,pidfile.rs,handoff.rs,update_guard.rs,scrollback.rs,history.rs— plus two large subsystems of its own:ssh/(authentication 66 KB, forwarding 53 KB, SFTP 37 KB, known hosts 36 KB) andinstall/(70 KB, with 63 KB more for WSL and 19 KB each for Windows hosts and proxies). - src/
- The desktop application:
main.rsat 49 KB, and 105 files undersrc/ui/totalling 5.4 MB, of whichapp.rsis 594 KB,tree_sync.rs231 KB,tab_sidebar.rs196 KB,switcher.rs180 KB andsettings.rs166 KB;src/terminal/is 32 files and 1.8 MB, led byview.rsat 677 KB,search.rsat 126 KB andinput.rsat 54 KB. A separate 173 KB updater binary sits insrc/bin/. - crates/tty7-cli/
- The non-interactive client: seventeen files, with
commands.rsat 207 KB andcli.rsat 43 KB, a 51 KB end-to-end test, and the addressing model the whole agent loop depends on —%83for a pane,@7for a tab, a name or id for a workspace. - mobile/
- A Tauri application with its own lockfile and its own release tag:
src/main.tsis 118 KB andstyle.css40 KB,DESIGN.mdis 22 KB of design system and.impeccable/design.json37 KB of tokens, with generated Android and iOS projects and ascripts/testflight.shthat puts the app icons back after each regeneration. - crates/tty7-gateway/, crates/tty7-mobile-proto/, crates/tty7-mobile-client/
- The phone path: a gateway the phone pairs with (
serve.rs28 KB,state.rs16 KB,service.rs14 KB, a poller, and abridge.rsintegration test), a 23 KB protocol crate, and a 12 KB client with an mDNS test. - docs/, skills/tty7/, .github/
- Forty document pages across nine sections with thirty images and a docs config; an agent-facing skill (
SKILL.md18 KB, a 25 KB command reference, a 13 KB delegation reference); and the release machinery — four workflows and eleven scripts, from bundling for three platforms to the host-boundary check.
Choices, and what they beat
The shells belong to a background server, not the window over running a multiplexer inside the terminal to keep them alive
The README opens with that problem: most terminals tie your shells to a window, so people run tmux inside them, which works but means a second set of keys and a second config file just to get around the window. Moving the shells into a daemon makes quitting the app a no-op, makes the command line and the phone equal clients of the same panes, and makes a remote workspace the same program running elsewhere rather than a feature of its own.
Leave the agents in their own PTY over wrapping or proxying them
Documented in one line: “The agent you start is the real one, running in an ordinary PTY. Simple things are more likely to keep working.” What follows is status, read from a hook installed into each agent’s own configuration, one click per agent, rather than an interception layer that would have to be kept in step with every CLI the project recognises.
Take status from the agent itself over reading the screen for a sentinel
The CLI documentation says a screen is a rectangle: text that scrolled off the top is gone, a wrapped line is not one line, and an exit code was never on the screen, so it recommends writing the answer to a file. Status arrives over a channel installed into the agent’s configuration, which is what lets
tty7 waitblock until an agent is waiting or done instead of polling.One workspace is driven by one window at a time over letting a local and a remote window drive the same panes
Both drove them at once, and the visible result was pane size flapping because the last resize won, with TUIs reflowing constantly (pull request 1042). The rule applies to the window on the daemon’s own machine as well as to remote clients, and lives in a small pure state shared with the remote path.
Remote is the same server, with nothing synced over a workspace that synchronises files or forwards a session
The README frames remote as the local case with the server somewhere else, so one daemon, one machine tree and one set of panes serve both, with the host boundary enforced by a conformance test and a CI script. It also explains where the bugs come from: a remote pane is a real SSH session, so a default limit of ten sessions per connection becomes a product limit (1034).
Read fromREADME.md, docs/agents/overview.mdx, docs/cli/overview.mdx, mobile/DESIGN.md, the pull request and issue bodies numbered 1029 to 1058, and the complete 754-file tree with byte sizes.
Build log
6 stages- 01
Twelve weeks, 1,546 commits, and a version line restarted in July
The first commit is dated 2026-07-06 and reads “a GPU-rendered, daemon-backed terminal in pure Rust”; the newest in the report is a link-parser fix on 2026-09-30, with 1,546 commits in between — 543 in July, 562 in August, 441 in September. One account wrote 1,302 of them; the other 244 come from thirty-three accounts, one with 89 commits and one with 30, and 1,544 of the 1,546 are linked to a GitHub account at all. Of the 316 commits that carry a co-author trailer, 92 name a Claude model, the largest group Opus variants, and the owner co-authors himself 199 times. The twenty releases in the report start at v0.16.0 on 2026-07-15 and pass through four versions in two days: v0.17.0 and v26.7.0 both land on 2026-07-16, after which the numbering is a year and a month — 26.7.x through 26.9.4 on 2026-09-29, whose own title claims an IDE-level code editor, a v5 redesign and a GitHub tab, while v26.8.3 calls itself a 151-fix polish pass. The nightly is a rolling prerelease tag rather than a version, the phone app has its own tags (mobile-v0.1.1 and mobile-v0.1.2, both on 2026-09-30), and the changelog committed to the repository is 376 KB.
- 02
The shells belong to the server, and the server must be replaceable
The README states the design as one decision: the shells belong to a server running in the background and the window only shows them, so closing the window does nothing to them. The server is
crates/tty7-core/src/daemon/—server.rsat 68 KB,control.rsat 110 KB,pane.rsat 316 KB,spawn.rsat 94 KB,protocol.rsat 104 KB,router.rsat 52 KB — with the parts a long-lived process needs around it:singleton.rs,pidfile.rs,handoff.rs,update_guard.rs,scrollback.rsandhistory.rs. A separate 173 KB updater binary sits alongside it, withhandoff.rsandupdate_guard.rsinside the daemon. What the daemon believes about the world is a machine tree inmachine.json: pane records holding cwd, shell, SSH spec and agent facts, plus — added in pull request 1037 — aclosedlist of recently closed tabs with their layout and aclosed_attime, so reopening a tab survives a GUI restart and is visible to every other window on that workspace instead of living in one window’s memory. A reboot is the case the design does not pretend to solve: the processes are gone, and what returns is the layout, the last of what was on screen and, for agents whose hook is installed, the same conversation. - 03
gpui on a private fork, a VT core from Alacritty, and a screen that is a rectangle
The subtitle is the stack: pure Rust, GPU rendering on Zed’s gpui, VT core from Alacritty. gpui paints each text line into a scene layer whose bounds decide its draw order against later primitives, and those bounds were computed from the unaligned origin, so right-aligned glyphs fell outside their own layer and drew through the buttons that appear when a row is hovered; the fix is a
layer_boundshelper in a fork of Zed,l0ng-ai/zed@3d46ee70fb(1030). A second came from a component library: the title bar reserves an 80pt lead for the macOS traffic lights, so the centred Search Everywhere box sat 40pt right of the terminal column (1036). The repository carrieskitty_graphics.rs(87 KB) andinput.rs(54 KB), and on Windows it ships Microsoft’sconpty.dllandOpenConsole.exe, version 1.24.260710001, for x64 and arm64 rather than trusting the in-box pair (1043). One open issue reports the physical Escape key producing nothing in a TUI using the Kitty Keyboard Protocol on Windows; the author could not reproduce it and answered with probes rather than a fix — a unit test for the encoding, both ConPTY builds passing the sequence through, and a synthetic key event under Python and Node. Performance is measured by committed scripts: 95 ms for an 11 MBcat, DOOM-fire at 888 fps. - 04
Agents that run agents, without wrapping them
Twenty-six coding CLIs are recognised from the command running in a pane, and detection sees through a full path, a
.cmdor.exeon Windows, leading environment assignments and an interpreter in front (node .../claude/cli.js); a wrapper of your own is mapped to an agent inconfig.json. Status is not: it comes from the agent itself over a channel tty7 installs into that agent’s own configuration, one click per agent, powering the status dots, notifications, the tray icon,tty7 waitand resume after a reboot. The asker need not be a person:tty7 split,send,waitandcaptureare the whole loop. The documentation is clear about where this breaks — a screen is a rectangle, and an exit code was never on it. The README says the agents are not wrapped or proxied, in one line: “The agent you start is the real one, running in an ordinary PTY. Simple things are more likely to keep working.” Behind that sitagent_hooks.rs(163 KB),cli_agent.rs(109 KB) andagent_history.rs(72 KB); it also ships an agent skill (skills/tty7/SKILL.md18 KB, a 25 KB command reference, a 13 KB delegation reference) installed withnpx skills add l0ng-ai/tty7. The CLI is a thin non-interactive client: a pane address such as%42is stable for the life of the pane, while a tab address such as@7shifts whenever anything is created or closed. - 05
Remote is the same server, which is where the hard bugs live
A remote workspace is the same daemon on the other machine: tabs, panes, git and diffs live over there and nothing is copied, reached through the project’s own Rust SSH client — keychain profiles, jump hosts, SFTP, port forwarding, and a
tty7-serverthat installs once without root. The boundary is real enough to have its own script:daemon/install/is 70 KB pluswsl.rsat 63 KB, and.github/scripts/check-host-boundary.shis kept for exactly that line. The bugs are where the interest is. A 17-pane remote workspace hung for over ten seconds because sshd allows ten sessions per connection and every remote pane is one: the eleventh open was refused, and the connection was retired while ten panes still used it. Reattach made it worse — any failure other than silence was read as the pane being gone, so it spawned a fresh shell that auto-ranclaude --resumewhile the original was still alive (1034). Elsewhere, the window on the daemon’s own machine skipped workspace takeover, so a remote client and the local window drove the same panes at once, the last resize won and TUIs reflowed; the rule written down afterwards is one workspace to one window at a time (1042). Windows hosts added their own run of POSIX assumptions, fromsh -ctosetsidandkill -TERM(1041). - 06
Nightly tables, UTC build numbers, and notes that say what was not checked
Four workflows — ci at 19 KB, nightly at 26 KB, release at 23 KB, mobile at 8 KB — and eleven scripts under
.github/scripts/, among them a macOS bundler, an installer script and assertions about the binaries that come out. The nightly notes open with a download table for all four platforms, built from the files that night actually produced, so a failed build is left out rather than linked dead (1054, 1055). The Windows ARM64 leg is cross-compiled and marked experimental until it has shipped once, so its failure drops the ARM64 packages instead of blocking the release (1043). The recorded failures are ordinary: TestFlight build numbers were the local time, so a machine in UTC+8 numbered builds eight hours ahead of the UTC runner and a CI upload of the same version within eight hours came out lower and was refused (1050); a certificate check matched one fixed string while newer apksigners name the signer by SDK range (1047). Two notes are worth more than the fixes: a mobile change was checked in the iOS simulator in dark theme only — “Not yet checked in the light theme or on a device” — and a stuck-relay fix skipped the pull-request path: “shipping a TestFlight build from the branch first” (1039, 1057). The README itself was rewritten in a pull request to lead with three pillars and the line “The terminal that outlives its window” instead of a feature list (1046).
Adjacent records
All records →No. 073
Zeron
A Rust desktop app that runs the coding agents you already use — Claude Code, Codex, Cursor, Devin, Grok, Hermes, Pi and Antigravity — on your own machine, with no account required, and syncs the sessions to your other devices only if you sign in.
No. 061
Reticle
An MCP server and a dev-only SDK that let a coding agent read and drive a running web or desktop app from the inside, then answer with a verdict and the file and line to fix instead of a screenshot.
No. 077
Lody
A workspace where a team shares the coding agents it already runs: connect a machine, bring Claude Code, Codex, Kimi or any other agent that speaks the protocol, and dispatch work from desktop, phone, web or terminal while sessions delegate to each other and the code stays on the machine its owner connected.