wezterm

Activity, over time

Daily observations from the public event archive.

Attention

Daily stars & forks

Loading attention chart

Star accumulation

Cumulative stars

Loading star accumulation chart

Pull requests

Daily opens & merges

Loading pull requests chart

Conversations

Daily issues & comments

Loading conversations chart

Community

Daily accounts & reviews

Loading community chart

Releases

Daily releases

Loading releases chart

Mentions

4posts · 30d
Nov 30 posts
  1. Your Terminal Spots Password Prompts From Two TTY Bits. sudo's 2025 Fix Breaks the Check - Book: AI Agents Pocket Guide - The series: Pocket Guides for Developers — 8 short books on agents, RAG, prompts, observability, events, databases and system design — the whole series - My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools - Me: xgabriel.com | GitHub --- You type sudo apt upgrade and the prompt says Password:. Nothing appears as you type. Your shell never sees those keys. sudo reads them straight from the terminal device. But your terminal app sees every single one, because it is the program that sends them down the pseudo-terminal in the first place. So the terminal is holding your password in its hands for a moment. If it has a feature that remembers what you type (ghost-text suggestions, a session recorder, an agent that reads the scrollback), how does it know to look away? On macOS and Linux the usual answer starts with one bit in a struct called termios. You can watch it flip from the other side of the pty with a short Python script, and it is a weaker signal than it looks. Since late 2025 it is weaker still, because sudo changed how it reads passwords. The bit: ECHO in c_lflag Every terminal device on a POSIX system carries a termios struct. Its local-mode field, c_lflag, holds the flags that decide how the line discipline treats your keystrokes. Two of them matter here. ECHO means "echo input characters", and ICANON turns on canonical mode, where "input is made available line by line" (termios(3)). A program that wants a secret clears ECHO, reads, and puts it back. OpenSSH's readpassphrase does exactly that: unless the caller asks for echo, it runs term.c_lflag &= ~(ECHO | ECHONL) and leaves ICANON alone (readpassphrase.c). Python's own termios docs show the same pattern as their example: copy the attributes, clear termios.ECHO in the lflag slot, read a line, restore in a finally. You can watch this from a second terminal with stty. In terminal A, run tty to get its device name, then start something that asks for a passphrase and leave it sitting at the prompt. In terminal B: # Linux (GNU stty) stty -F /dev/pts/4 -a # macOS (BSD stty) stty -f /dev/ttys004 -a Use the device name tty printed. In the output, a leading - means the setting is off, so -echo is the bit you are after, and icanon without a dash means canonical mode is still on (GNU stty, BSD stty). Run the same stty while terminal A sits at a plain bash prompt and you will also see -echo. GNU Readline, which bash uses to edit your command line, runs tiop->c_lflag &= ~(ICANON | ECHO) and draws every character itself. Full-screen programs do the same thing through raw mode: cfmakeraw() clears ECHO, ICANON and a few more (termios(3)). "Echo is off" alone describes most interactive programs you run. That is why terminals that detect password prompts check two bits. WezTerm looks at the pty's termios "to see whether local echo is disabled and canonical input is enabled", and only then turns the cursor into a lock. Ghostty reads the same pair with tcgetattr on the master and draws the same lock glyph. Read it from the master side A terminal emulator holds the master end of the pty. The program in it, your shell or sudo, has the slave end. WezTerm's pty code gets the termios with tcgetattr on the master's file descriptor, and so does Ghostty. You can do the same in Python, where pty.fork() hands the parent a descriptor "connected to the child's controlling terminal". This script starts a command on a fresh pty, passes your keys through, and prints a note whenever ECHO or ICANON changes: # echowatch.py: run a command on a pty, report ECHO/ICANON import os, pty, select, sys, termios, tty pid, fd = pty.fork() if pid == 0: os.execvp(sys.argv[1], sys.argv[1:]) saved = termios.tcgetattr(0) tty.setraw(0) # our terminal stops echoing; the pty decides last = None try: while True: try: lflag = termios.tcgetattr(fd)[3] # master side except termios.error: break mode = (bool(lflag & termios.ECHO), bool(lflag & termios.ICANON)) if mode != last: note = f"\r\n[echo={mode[0]} icanon={mode[1]}]\r\n" os.write(2, note.encode()) last = mode ready, _, _ = select.select([fd, 0], [], [], 0.1) if 0 in ready: os.write(fd, os.read(0, 1024)) if fd in ready: try: data = os.read(fd, 1024) except OSError: # some systems raise EIO at exit break if not data: # others return EOF break os.write(1, data) finally: termios.tcsetattr(0, termios.TCSAFLUSH, saved) os.waitpid(pid, 0) The tty.setraw(0) line matters. Without it, your outer terminal would echo the password locally while the inner pty politely hid it. Point the watcher at the plainest password prompt there is: python3 echowatch.py python3 -c \ "import getpass; getpass.getpass()" getpass prompts "without echoing" and reads from /dev/tty, which here is the pty (getpass docs). When the prompt appears, the note should switch to echo=False with icanon=True: the pair WezTerm and Ghostty treat as a password prompt. Then try python3 echowatch.py bash and watch the plain bash prompt report both bits off, as Readline's code says it will. I haven't run this myself, so treat those notes as what the man pages and source code predict, and trust your own run over this paragraph. Where the bit lies The two-bit rule is a heuristic, and its own docs say so. Ghostty's config reference says password prompt detection "is based on heuristics and may not always work as expected" (Ghostty docs). Here is where it breaks. ssh and tmux. When you ssh to a server, the OpenSSH client puts your local terminal into raw mode, clearing ISIG, ICANON, ECHO and more for the whole session (sshtty.c). The remote sudo flips bits on a pty on the remote machine, which your terminal cannot read. tmux does the same locally: your terminal talks to tmux, and the programs in tmux panes live on ptys tmux owns. WezTerm's docs say its check "will not work with tmux or remote processes spawned via ssh". Prompts that draw their own mask. A prompt that shows * per key has to see each key as you press it, so it turns canonical mode off too. Python's getpass gained an echo_char parameter in 3.14, and the docs say that with it set "the terminal will be configured to operate in noncanonical mode" (getpass docs). sudo-rs made pwfeedback the default in 0.2.13 on 2026-03-10, and Ubuntu, which switched to sudo-rs in 25.10, now shows asterisks at the sudo prompt in 26.04 (omgubuntu.co.uk). To a two-bit check, those prompts look like Readline. sudo itself, since late 2025. sudo-rs 0.2.10 fixed a bug where "a partially typed password would be output to standard input if a timeout occurred" when pwfeedback was off (sudo-rs changelog). It is CVE-2025-64170, rated 3.8 (Low). The root cause, per Wiz's write-up, was canonical mode left on during the timed read. The original sudo hit the same class of bug. A November 2025 commit, "tgetpass: Use cbreak mode if possible even if pwfeedback is disabled", says it fixes pending input being "echoed after sudo exits" when sudo is killed, and that "the password is read one character at a time rather than by line" (sudo ChangeLog). sudo's current tgetpass.c calls sudo_term_cbreak, which clears ECHO | ECHONL | ICANON | IEXTEN (term.c). So the fix that made sudo safer also takes ICANON off at the prompt, so a sudo built from that code shows the same two bits as a bash prompt. Which sudo release ships it depends on your distro, so check yours with stty before you trust a lock icon. Why this matters more with agents in the terminal In normal operation none of this touches your shell history. The shell isn't the program reading the password, so ~/.bash_history doesn't get it. The 2025 sudo bugs above were the exception: leftover keystrokes could reach the shell after sudo exited. The risk sits one layer up, in features that watch the terminal itself: autosuggest that learns from what you typed into the pane, recordings, and coding agents that run in the same terminal or read its scrollback. That layer sees the raw keystrokes, because it writes them into the pty master. A feature built there needs its own answer to "was that a secret?", and the termios bit is the obvious first answer. The previous section is why it can't be the only one. What Hermes 2.3.2 does instead I build Hermes IDE, so weigh this section with that in mind. Its terminal has ghost-text suggestions from your command history, and release 2.3.2 (October 13, 2026) lists two fixes: "What you type at a hidden password prompt (sudo, ssh, a script asking for a passphrase) is never remembered or suggested," and commands that carry a secret are never shown as a suggestion or as faded text after the cursor. Your shell's own history is not changed. The history recorder does not read the ECHO bit. The code in TerminalPool.ts records a typed line only when the shell is the foreground program and the pane is not on the alternate screen, so lines typed while another program holds the foreground are skipped before any other check. For a line that passes that gate, it waits 500 ms after Enter and reads the line back from the screen. The comment says it plainly: "a line the terminal did not show is never remembered." A prompt with echo off shows nothing, and a masked prompt shows asterisks rather than your text, so either way the line is dropped. The second fix is a pattern filter, secrets.ts. It drops lines with known token shapes (GitHub, AWS, Stripe, JWTs, private key headers and more), sensitive variables being set, flags like --password and --token, auth headers and Bearer values, and URLs with user:pass@ in them. Its doc comment sets the trade-off: "a missed suggestion costs a few keystrokes, a shown secret can end up on a shared screen or recording." Hermes is free, source-available under BSL 1.1, and runs on macOS, Windows and Linux. It is not affiliated with Nous Research, Anthropic, OpenAI or any agent vendor. Download it or read the code on GitHub. Check your own setup Run echowatch.py against the prompts you actually hit: sudo -k true, an ssh-keygen passphrase, and the password prompt of whatever CLI you use daily. Then run it with ssh and tmux as the command and watch the bits stay off for the whole session. If your terminal draws a lock icon, try it at a sudo prompt with pwfeedback on. If a tool you depend on decides "secret or not" from termios alone, you now know the three places to test it. --- If this was useful The pattern here is the one that keeps showing up with agents: a guardrail built on one signal works until the signal changes under it. The AI Agents Pocket Guide covers the patterns for building autonomous systems with LLMs, including guardrails that don't rest on a single signal. It is one of 8 short books in Pocket Guides for Developers, covering agents, RAG, prompts, observability, events, databases and system design. ![AI Agents Pocket Guide: Patterns for Building Autonomous Systems with LLMs](amazon.com)

    1 reaction
  2. Closing a Terminal Sends Your Coding Agent SIGHUP. How Session Hosts Keep It Alive - Book: System Design Pocket Guide: Interviews - The series: Pocket Guides for Developers — 8 short books on agents, RAG, prompts, observability, events, databases and system design — the whole series - My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools - Me: xgabriel.com | GitHub --- You hand a coding agent a long refactor, watch it start on the test suite, and close the terminal window, because the agent is doing the work now. When you open a new window, the process is gone, along with anything it had not written to disk. Your terminal app never went looking for the agent. Two hops killed it. The kernel told your shell that its terminal had hung up, and the shell passed that on, as SIGHUP, to every job it owned. The usual fixes, nohup, disown, setsid and tmux, each cut a different hop, and only one of them leaves the agent with a terminal you can type into again. You can reproduce every case below in a few minutes with ps. A sleep stands in for Claude Code or Codex, because it holds still and has no opinion about signals. Four numbers that decide who dies Unix groups processes twice. A process group is a job: the processes one command line started, so Ctrl+C reaches all of them. A session is a set of process groups that share one controlling terminal, and the process that created the session is its leader (credentials(7)). In a terminal window, the leader is your shell. Open a fresh window and look at your shell and one background job: sleep 600 & # Linux (procps) ps -o pid,ppid,pgid,sid,tpgid,tty,comm -p "$$,$!" # macOS: there is no sid column ps -o pid,ppid,pgid,tpgid,tty,comm -p "$$,$!" Four of those columns decide who dies: PID, PGID, SID and TPGID. The shell's PID equals its SID, because it leads the session. sleep has a PGID of its own, because job control puts every job in its own group. Both rows show the same TTY, the slave side of the window's pty. TPGID is the terminal's foreground group: while you sit at the prompt it is the shell's group, and while an agent runs in the foreground it is the agent's. The macOS line drops a column on purpose. Apple's ps has no sid keyword at all, and the closest one, sess, prints a kernel session pointer in hex instead of an ID (adv_cmds keyword.c). On a Mac, PGID, TPGID and TTY tell you enough. What happens when the window closes A terminal window holds the master side of a pseudo-terminal pair. Your shell and everything it starts talk to the slave side. Closing the window closes the master, either because the app closes it or because the app exits. On Linux, the pty driver reacts to a closing master by calling tty_vhangup on the slave (drivers/tty/pty.c). The hangup walks every process in the terminal's session. It sends SIGHUP and SIGCONT to the session leader, your shell, and clears the controlling terminal of every process in the session that pointed at it (tty_jobctrl.c). From then on a read from that tty returns 0, end of file, and a write fails with EIO (tty_io.c). POSIX states the same rules for any terminal that hangs up: SIGHUP to the controlling process, end of file on read, EIO on write (XBD 11.1.10). At the moment of the hangup, the kernel signalled one process: the shell. The second hop is the shell's own policy. Bash exits on SIGHUP, and before it does, an interactive bash "resends the SIGHUP to all jobs, running or stopped" (Bash manual). zsh, the default login shell on macOS since 10.15 (Apple), has a HUP option, on by default, that sends SIGHUP to running jobs when the shell exits. An agent running in the foreground is a job like any other, so it gets the same SIGHUP from the shell. It can get a second one when the shell exits: POSIX says the exit of a controlling process sends SIGHUP to each process in the terminal's foreground group (POSIX _exit), and Linux remembers which group that was when the terminal hung up (tty_jobctrl.c). So a foreground agent is signalled even by a shell that relays nothing. If it ignored both, the terminal under it still answers every read with end of file. !A blank terminal window snapping shut sends one orange signal to a shell figure, which relays smaller signals down to a row of process figures Two hops: the kernel signals the session leader, and the shell relays SIGHUP to its jobs. Five sleeps, one closed window Give each technique its own duration so you can tell the survivors apart. Run these in one window, in bash or zsh: sleep 601 & # plain background job nohup sleep 602 & # SIGHUP ignored sleep 603 & disown # zsh also: sleep 603 &! setsid -f sleep 604 # Linux only, util-linux tmux new -d -s agent 'sleep 605' On a Mac, replace the setsid line. macOS has the setsid() system call but no setsid command: on Linux that command comes from the util-linux package (setsid(1)), which macOS does not ship. Perl's POSIX module can make the call for you: perl -MPOSIX -e 'fork and exit; POSIX::setsid(); exec @ARGV' \ sleep 604 </dev/null >/dev/null 2>&1 The fork matters: setsid() fails with EPERM when the caller already leads a process group (setsid(2)), and a command your shell started as a job leads its group. That is also why the util-linux tool forks on its own in that case, and -f makes it fork every time. Now close the window, open a new one and list what is left: ps -A -o pid,ppid,pgid,tty,command | grep '[s]leep 60' Here is what each line went through: - sleep 601 was a job of the shell, so the shell's relayed SIGHUP ended it. - sleep 602 got the same relayed SIGHUP and ignored it. nohup sets SIGHUP to ignored before it runs the command, and appends output to nohup.out when stdout is a terminal (POSIX nohup). - sleep 603 never got a signal. disown removes the job from the shell's job table so the shell has nothing to relay to it (Bash manual), and the kernel only signalled the session leader. - sleep 604 lived in a different session with no controlling terminal (setsid(2)). The hangup walked a session it was never part of. - sleep 605 belongs to the tmux server, which gets its own section next. On Linux, the TTY column for 602 and 603 now reads ?, because the hangup cleared their controlling terminal. One trap with disown: a process group that becomes orphaned while one of its members is stopped gets SIGHUP followed by SIGCONT (POSIX _exit). Press Ctrl+Z on an agent, disown it, close the window, and it can still die. Surviving the signal is not keeping the terminal Four sleeps survived, and for sleep that is the whole story. An agent draws a screen, reads your keys and stops to ask before it runs a command. After nohup or disown, the terminal under it is hung up: every read is end of file and every write is EIO. After setsid, there was never a terminal at all. The process may be alive, but nothing can show you its next question or carry your answer back, and what it does about that is up to the agent. tmux is the only line in the experiment that kept a usable terminal, because the agent never had your window as its terminal. When tmux starts its server, it calls daemon(1, 0) (proc.c), which detaches it from the controlling terminal and points its stdin, stdout and stderr at /dev/null (daemon(3)). Each pane is a separate pseudo-terminal that the server opened and reads from. The tmux you type is only a client: "the server and each client are separate processes which communicate through a socket in /tmp" (tmux(1)). Closing your window hangs up the window's pty. If you had attached to the session in that window, the tmux client goes down with the shell. On the other side of the socket, the server still holds the pane, and the agent is still running in it. tmux attach -t agent from a new window connects a new client to the same pane. The hangup never reached the agent's terminal, because nothing in the agent's session was attached to your window. !A sturdy black tower holds orange cables plugged into small glowing terminal screens with tiny worker figures, while an app window beside it fades away The host keeps every pty master. Windows come and go as clients. The design every agent host needs Strip tmux down to what made it work, and any app that wants agents to outlive its window needs this list: 1. A separate long-lived process in its own session that ignores SIGHUP, so a dying UI or terminal can't take it along. 2. That process holds the pty master for every agent, and each agent runs in its own session with its pty as the controlling terminal. 3. The UI is a client. It connects over a socket only your user can open, and when it goes away the sessions keep running, unattached. 4. Output that arrives while nobody is attached goes into a buffer, so a returning client can replay what it missed and ask the program to redraw. 5. Replacing the UI binary leaves the running host alone, and the two sides check a protocol version before they talk. 6. The host exits once it has no sessions, so it never lingers as a stray daemon. I build Hermes IDE, so weigh this part with that in mind. Its session host follows that list, and the source is public. session_host.rs describes hermes-pty-host as a small background process that "owns the PTYs and their programs". The app starts it when the first session needs it, from a copy keyed by the app version, so an update "leaves the running host untouched". The app attaches over a user-only Unix socket with a token, treats a host that speaks another protocol version as unusable, and on return "reattaches to the sessions the host still has, replays the output it missed and nudges the program to repaint". The host's main.rs calls setsid() under the comment "Own session: the app's terminal or death must never take the host with it." server.rs ignores SIGHUP at startup, keeps a 2 MiB ring of output per session by default, treats a disconnected app as "its session keeps running, unattached", and exits after a stretch with no sessions. The ptys come from wezterm's portable-pty, which calls setsid() in each spawned program before exec and can make the pty its controlling terminal (unix.rs). That is what backs the README line that on macOS and Linux "agents keep working while Hermes quits, updates or crashes, and you reattach where they left off." Windows is the gap. The same session_host.rs says ConPTY "cannot move between processes", so on Windows the host reports itself unsupported and sessions stay inside the app. On Windows, or when an agent has to outlive the laptop itself, tmux on a remote box over SSH is still the tool. Hermes is free, source-available under BSL 1.1, runs on macOS, Windows and Linux, and is not affiliated with Nous Research, Anthropic, OpenAI or any agent vendor. Download it or read the code on GitHub. --- If this was useful The host in the last section is a small system design problem: a process boundary, a socket protocol, a buffer with a size limit, a version check, and a decision about what happens when the client disappears. The System Design Pocket Guide: Interviews walks through 15 real system designs step by step and makes those trade-offs out loud. It is one of 8 short books in the Pocket Guides for Developers series, covering agents, RAG, prompts, observability, events, databases and system design. ![System Design Pocket Guide: Interviews — 15 Real System Designs, Step by Step](amazon.com)

    1 reaction
  3. DEV · · @hidetzu

    My Mac Is Just a Screen Now: 3 Things That Broke With WezTerm SSHMUX Homebrew and pacman both told me my WezTerm was 20240203. They were not the same build, and WezTerm's SSH multiplexing will not connect unless both ends speak the same protocol version. That was the first of three things that broke when I stopped developing on two machines and split them by role instead: the Mac is a screen and keyboard, the Arch Linux box is the only dev environment. Every one of the three was a boundary problem, and once I saw that, debugging got much easier. All the config lives in my dotfiles: hidetzu/dotfiles The setup I used to keep both machines dev-ready. That meant two toolchains, two checkouts, two installs of every AI CLI, all kept in sync by hand. When they drifted, something worked on one machine and broke on the other. So I split them: - Mac (client) — the screen and the input. No development happens here - Arch (devhost) — source, toolchains, LSP servers, Docker, Claude Code. All of it lives only here !Diagram 1 The terminal talks to the devhost over WezTerm's SSH multiplexing, and VS Code uses its Remote SSH extension. The dotfiles follow the same split: | Role | Machine | What goes there | |---|---|---| | client | macOS | WezTerm, VS Code Remote SSH config, Brewfile | | devhost | Arch Linux | Source, LSP servers, WezTerm mux server, Claude Code | | common | Both | git, fish, starship, Neovim config | The Mac still gets my shell and editor config. But code only runs on the devhost. The one thing both machines must agree on is the piece that connects them: WezTerm. Why SSHMUX I had moved from tmux + Alacritty to WezTerm, and at first I reached the devhost with plain ssh. Drop the connection and the panes died with it. Leaving tmux had cost me the one thing tmux was there for. WezTerm's SSHMUX gets it back. It starts a WezTerm mux server on the remote host over SSH — a server that holds the panes and shows them to whichever client connects. SSHMUX: is the prefix WezTerm gives this kind of domain. -- client/config/wezterm/wezterm.lua table.insert(config.ssh_domains, { name = "SSHMUX:" .. host, remote_address = host, multiplexing = "WezTerm", remote_wezterm_path = "~/.local/bin/wezterm-mux", }) The panes live on the devhost, and the Mac only displays them. That is the role split, enforced by the terminal: - Lose the network or close the laptop, and the panes survive on the devhost - Splits and new tabs are created on the devhost, in the same directory - No tmux in between, so there is one set of tabs and panes, not two A dev command that follows the split I open projects with a small dev command, and it is split the same way: $ dev dotfiles # open the devhost's dotfiles in Neovim, in a new tab $ dev -c dotfiles # open it in VS Code over Remote SSH !Diagram 2 - The devhost knows what exists. The candidate list comes from it - The Mac chooses. fzf runs locally. Running it over SSH adds a round trip to every keystroke - The devhost opens. The pane is created there through SSHMUX What broke at the boundary Splitting the roles puts a boundary between the machines. Things that used to happen on one machine now cross it. Three of them broke. 1. Same version string, different builds The SSHMUX client and server compare a mux protocol version (WezTerm calls it the codec version) when they connect. If it differs, the client refuses with an IncompatibleVersionError. Leaving this to the package managers did not work. Homebrew's stable wezterm cask is 20240203-110809. Arch's package also says 20240203, but read the whole string: $ pacman -Q wezterm wezterm 20240203.110809.5046fc22.r869.g76b606ec5-3 $ /usr/bin/wezterm --version wezterm 20260716-195552-76b606ec r869 is 869 commits past the 20240203 tag. Arch ships a git snapshot under the old release name, and the binary reports a 2026 build. Same label, different program. So I install the same nightly build on both sides, explicitly. Not because I wanted the latest features — it was the simplest way to guarantee both ends are identical. - Mac: the Homebrew cask wezterm@nightly - devhost: the same build, extracted from the AppImage to ~/.local/bin by a script (wezterm-mux-install). The pacman package stays untouched - A third script, wezterm-match, checks that they agree $ wezterm-match client: 20261010-083911-e2a98e1b arch: 20261010-083911-e2a98e1b ok: same build WezTerm publishes nightlies under a single nightly release tag that is overwritten each time, so only the latest build is downloadable. Upgrading means upgrading both sides together. 2. The Mac's environment leaks into the devhost When wezterm cli spawn on the Mac passes a command to a new devhost pane, it sends the Mac's environment along with it: $ wezterm cli spawn --domain-name SSHMUX:arch --cwd /tmp -- \ sh -c 'echo "HOME=$HOME"; echo "SHELL=$SHELL"; sleep 30' HOME=/Users/kawashima SHELL=/opt/homebrew/bin/fish Neither path exists on Arch. Without --cwd, the devhost tries to start in that HOME, finds no such directory, and the pane never starts. So dev spawns the pane with no command, then types nvim . into it. A pane opened that way builds its environment on the devhost: HOME=/home/kawashima SHELL=/usr/bin/bash 3. The devhost's knowledge doesn't reach the Mac The leak also runs the other way. - Copying the last command's output. My shell emits OSC 133, the escape sequences that tell the terminal where the prompt ends and the output begins. That information lives in the devhost's mux server and never reaches the Mac, so the copy that worked in local panes does nothing. This is WezTerm #5141, "Jump to semantic regions not working through non-local domains", still open. I replaced it with a copy that finds my starship prompt in the screen text and cuts from there - Neovim's clipboard. OSC 52 can push text to the Mac's clipboard just fine. But my config decided "am I over SSH?" by checking SSH_TTY, and SSHMUX panes don't have it. I changed the check Both features quietly assumed the terminal and the shell were on the same machine. The role split broke that assumption. Trade-offs | Gave up | Got | |---|---| | Connecting from any terminal (this is WezTerm-only now) | One dev environment, in one place | | Not caring about WezTerm versions | WezTerm is the only thing to keep in sync | | macOS notifications (the unsigned nightly doesn't show them in my setup) | Panes that survive a dropped connection | There is an escape hatch. Next to SSHMUX:arch I keep a plain SSH domain, SSH:arch, with no mux. If the builds ever drift apart, I connect through that. The panes won't survive a disconnect, but work doesn't stop. > Note: Tested with WezTerm nightly 20261010-083911-e2a98e1b on both machines; the devhost's pacman package is 20240203.110809.5046fc22.r869.g76b606ec5-3. Each experiment was run once, by hand. I have not hit the version-mismatch error myself — I matched the builds from day one. The boundary is the debugging map Every failure above came from splitting one machine into two: - What must match: WezTerm, the one thing connecting both sides - What leaks in: the Mac's environment variables, into devhost panes - What doesn't come out: state that lives on the devhost, like semantic zones and SSH_TTY If you move to a thin-client setup, decide what lives on which side first. When something breaks, ask which boundary it crossed and in which direction. That question found all three of mine.

  4. Seems like this is a known “issue” with Wezterm, eg: wezterm#7728 plus many more. As I had assumed it may be due to a different choice of font renderer than what iTerm’s probably using. Anyhoo, on to alacritty and possibly ghostty tomorrow sometime, just […]

Latest stargazers

The last 10 distinct accounts we observed this year.

Most active participants

PR, issue, comment & review events in the past year.

Packages

3
PackageVersionDownloads · 30dTrend · 30d
taboutv0.3.0
v0.3.0——
v0.2.3——
v0.3.0——

README badges

Embed a badge in your README or website.

  • wez/wezterm reached #2 in daily stars on gitwal · Apr 1, 2021
Live mentions · last 30 days
wez/wezterm mentions in the last 30 days