l0ng-ai 3dc63e2d87 fix(daemon): find and reap a seat-holding daemon that lost both its names (#671)
A daemon can survive quit-and-stop with its endpoint unlinked and its
pidfile gone while still holding the singleton seat (#667). Every later
launch then spawns a daemon that stands down against the lock and times
out red, and nothing on the machine can recover: stop answers "not
running", ensure_running reaps only through the pidfile, and flock
cannot say who the holder is.

Two roads led there, and both are closed:

- The reap identified a daemon by proc_pidpath alone, which fails
  outright for a live process whose binary was deleted — every nightly
  update replacing the installation. The identity check now falls back
  to the kernel's comm name (proc_name on macOS, /proc/pid/comm on
  Linux, both recorded at exec and immune to deletion), strips Linux's
  " (deleted)" marker, and — decisively — no longer deletes the
  pidfile of a live process it cannot identify: the record was the only
  handle left on the survivor.

- When the pidfile is gone entirely, the pid the claimant now writes
  into daemon.lock at claim time is the handle of last resort. The lock
  file is never deleted and holding the flock is the definition of
  being the server, so while the seat is held its content names the
  holder; stop() and the reap fall back to it, and a confirmed reap
  clears the record (only under a momentarily-free seat) so a stale
  number cannot outlive its process. Unix-only: the Windows seat is
  share_mode(0), unreadable while held.

Every road back now clears a stranded seat, not just the GUI's:
ensure_running's stale cleanup is factored into spawn::reap_stranded,
tty7 server start runs it too, and tty7 server stop no longer takes
"nobody answered" for "nothing to stop" when the seat is still held.
A short grace keeps the reap away from a daemon that is merely
mid-handoff or mid-startup — where health is an answered handshake,
never a bare connect: a wedged daemon's listener still completes
connections out of the kernel's backlog. The startup-timeout errors
name the seat-holding pid, with the kill advice identity-gated so a
stale record never tells anyone to kill an innocent process.

Two liveness corrections round it out: a zombie now reads as dead — it
answers kill(pid, 0) like the living but holds no lock and no image,
and no signal can end it, so counting it alive spent both reap timeouts
on a corpse (the GUI never waits on the daemons it spawns, so crashed
daemons are zombies as a rule) — and stop() only pays the
process-exit wait for a shutdown it actually delivered, instead of
watching an unreached survivor not move for five seconds.

The guard tests were each verified to fail against the behavior they
pin (fallbacks, the handshake criterion, the grace, and the wait gate
removed by mutation) before being trusted green; the zombie probe
semantics (proc_pidinfo failing for a zombie that still answers signal
0) were measured, not assumed.
2026-08-17 15:11:16 +08:00

tty7

tty7

A terminal workbench: persistent sessions, remote work, agents.

Pure Rust · GPU rendering on Zed's gpui · VT core from Alacritty


CI Version Platforms License Discord

English · 简体中文


tty7 with a tab sidebar of agent sessions across several repos, running Claude Code

Why

  • 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
  • Editor-grade input — suggestions, completion, highlighting, history search
  • Remote development — files, repos, panes, and git data stay on the remote machine
  • Native SSH — profiles, SFTP, port forwarding, and jump hosts
  • Agent-aware — Claude Code, Codex & co.: status, notifications, git context
  • CLI + Skills — agents create panes, run commands, and inspect output

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

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 palette · ⌘ F scrollback search · nine themes · IME
Agent-aware per-pane detection (18 CLIs): status dot · notifications · branch + diff · resume after reboot · tray icon when input is needed
Remote workspaces remote files, repos, changes, diffs, worktrees, tabs, and panes · reconnect from any client and continue where you left off
CLI + Skills bundled tty7 CLI · agent skill · pane/workspace control · real PTY commands · output, process, port, and agent status
SSH native russh stack: profiles with keychain secrets · SFTP panel · port forwarding · jump hosts · one-time, unprivileged tty7-server install

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/.


S
Description
A terminal workbench in pure Rust: shells, persistent sessions, SSH, coding agents. GPU-rendered on Zed's gpui, VT core from Alacritty.
Readme Apache-2.0
34 MiB
Languages
Rust 99.1%
Shell 0.5%
PowerShell 0.2%
Inno Setup 0.1%