main
250 commits
(250 out of 446 generated)
bea5fe3
David van Munster
·
2026-08-11
build(nix): regenerate lockfile (#236)
4cab009
David van Munster
·
2026-08-11
build(nix): bump zig2nix to 0.16.0 (#235)
92f2425
Eric Bower
·
2026-08-11
fix(pty): preserve terminal width and prevent readline truncation in run tasks - Fetch terminal size in daemonize() before stdio redirection to /dev/null - Send .Resize before .Run in zmx run to match client terminal size - Default TERM to xterm-256color when unset/dumb to prevent readline horizontal scroll artifacts
347fbf4
Eric Bower
·
2026-08-11
docs: changelog
7a001c4
Eric Bower
·
2026-08-11
fix(daemon): sync pwd on IPC queries and add wait_for_cwd test helper Ensure daemon.cwd is updated from the terminal emulator state when handling IPC Info and History requests. This prevents zmx list from reporting stale working directory state if queried before the PTY read loop calls setPwd. Also add a deterministic wait_for_cwd helper to test_helper.bash so BATS OSC 7 tests poll zmx list until the expected CWD is populated, fixing host-side test race conditions.
e4e7ad7
Chance Zibolski
·
2026-08-05
fix(cwd): decode the OSC 7 cwd before the chdir
`Daemon.cwd` holds the OSC 7 value, which is percent-encoded, and nothing
decoded it before opening the directory. The chdir on session create
failed on any escaped character:
[warning] failed to open dir=/tmp/zmx%20spaced%20dir err=FileNotFound
The new session then silently landed in the daemon's inherited cwd.
`util.parseOsc7Cwd` decodes the value to an openable path and reports
whether its host is this machine. `Daemon.setCwd` keeps both: `cwd` stays
in `file://<host><path>` form so `zmx list` still shows the host, which is
what tells you a session is inside SSH, and `cwd_path` holds the decoded
path used for the chdir. A caller that supplies a plain path (`zmx run`,
`zmx attach`) gets a URI built by `util.toOsc7Cwd`, so the stored value
has one shape regardless of source.
`cwd_path` is left empty when the cwd is on another host, since OSC 7
crosses SSH boundaries and the directory does not exist here. That check
previously used `mem.eql` against gethostname(), so a missing host,
`localhost`, and short-name/FQDN mismatches all read as remote and
disabled the chdir even locally.
Refs #222
a0fc894
Chance Zibolski
·
2026-08-04
fix(attach): drop stray NUL from replayed OSC 7
The formatter's `extra.pwd` writes `terminal.pwd.items`, and
`Terminal.setPwd` appends a NUL sentinel to that buffer, so every OSC 7
we replayed carried a stray \x00 before the terminator:
\x1b]7;file://HOST/private/tmp\x00\x1b\\
Terminals that only apply the value tolerate it. One that records what
it receives persists the NUL and then fails to parse its own state back,
which is what left kitty unable to start.
Emit OSC 7 from `getPwd()` instead, which returns the same bytes without
the sentinel. `serializeTerminal` had the same bug, so `zmx history --vt`
was emitting it too.
Refs #222
00897d8
Eric Bower
·
2026-08-11
refactor: ZMX_TASK_COMPLETE now uses a 4ch hex id for task detection This ensures we are correctly scanning for the task that was actually triggered from the current daemon. A zmx session is allowed to `zmx run` to another session and then it immediately tails that command. That command will also output the ZMX_TASK_COMPLETE marker which could mark the parent session as complete erroneously. We now look for `ZMX_TASK_COMPLETE:wxyz:0`
b7033a8
Chance Zibolski
·
2026-08-05
build: fetch the zig tarball for the host arch
The Dockerfile hardcoded the x86_64 tarball, so on an arm64 host the
image ran under emulation and `zig build` died before compiling anything:
error: rosetta error: bss_size overflow
That made `zmx run build`, `test`, `fmt`, and `integration` from pico.sh
unusable on Apple silicon.
`uname -m` already reports the names zig uses (x86_64, aarch64), so
substituting it needs no mapping table. Unknown arches now fail with
their own name rather than a 404 from ziglang.org.
Also drop `-v` from tar, which printed a line per extracted file, and
remove the tarball after extracting it.
bdea415
Eric Bower
·
2026-08-03
docs: changelog
4f3739e
Varun Biniwale
·
2026-07-08
feat(attach): add ZMX_NO_DETACH_KEY to free up ctrl+\ for inner programs ctrl+\ as the detach key is hardcoded with no way to opt out, which conflicts with programs that use it themselves (e.g. vim's ctrl+\ ctrl+n to escape its own :terminal). Since the byte is intercepted in the client's input loop before it ever reaches the remote PTY, no remapping on the inner program's side can work around it. Setting ZMX_NO_DETACH_KEY (to any value) skips the ctrl+\ intercept so it passes through as normal input; zmx detach or closing the window still work as usual.
70476a7
Eric Bower
·
2026-08-03
chore: remove pty data from logs Closes: https://github.com/neurosnap/zmx/pull/227
85b045c
Eric Bower
·
2026-08-01
feat: track cwd We now update the session's cwd whenever it changes based on OSC7 ansi escape codes. Now when switching to session B from within session A, we now correctly set the dir to where session A left off. Because we are tracking cwd based on OSC7, embedded within cwd is the hostname (`std.Uri`) so we know not to try to chdir when the session is ssh'd into a remote machine. BREAKING CHANGE: static `start_cwd` has been replaced by dynamic `cwd`
3697982
Eric Bower
·
2026-08-02
fix(log): race between checking the length of the file and writing to it
0843272
Chance Zibolski
·
2026-08-01
fix: replay the window title on attach (#224) The formatter has no title extra and never emits OSC 0/1/2, so a client that attaches to an existing session shows whatever its terminal falls back to, usually the name of the client process, even though the title is tracked in the terminal state. Programs that set a title only emit it on their own schedule, so a shell reprints it at the next prompt but a long running program does not reprint it at all, leaving the wrong title for as long as it runs.
8a6d038
Eric Bower
·
2026-08-01
fix: max_scrollback buffer api for libghostty changed
027afd7
Eric Bower
·
2026-08-01
chore: update libghostty
85697d5
Chance Zibolski
·
2026-08-01
fix: build on macOS with zig 0.16.0 (#223) * fix: cast log_mode to mode_t for File.Permissions.fromMode cfg.log_mode is u32 while fromMode takes mode_t, which is u16 on macOS, so these two call sites fail to compile there. cfg.zig already casts for the equivalent Dir.Permissions calls. * fix: use the platform signal type in the wake handler The handler was declared with std.os.linux.SIG, so sigaction rejects it on platforms where that is not the native type and the build fails on macOS. posix.zig already re-exports SIG for this purpose.
266a733
Eric Bower
·
2026-07-31
fix(switch): reset screen and pass shell to next daemon
fa93c35
Eric Bower
·
2026-07-30
docs(daemon): copy tweaks to comment
a39b3d0
Eric Bower
·
2026-07-30
fix: revert umask and chdir
0b44313
Eric Bower
·
2026-07-30
docs: daemonize
6171338
Eric Bower
·
2026-07-30
chore: ensure robust daemon This is mostly for posterity: we setup the daemon process to chdir to "/" and set the umask to 0. This ensures the daemon is not on a dir that could be unmounted and then the unmount would fail (like a usb drive) and we reset the umask so the daemon doesn't unherit an unpredictable umask.
0d66096
Eric Bower
·
2026-07-27
refactor(daemon): restructure io and allocators Because we perform a double-fork when spawning a daemon we have to be careful about multithreading and mutex locks within io and allocators or else we could end up with a deadlock. I don't fully understand how this happens within the DebugAllocator but I've hit deadlocks previously. So I restructured the Daemon to not store io or an allocator and made it much more clear what is going on and why we have to create a new allocator after the double-fork. I also extracted the daemonize logic into its own file and set of fns mainly because that code doesn't need to change much and it is mostly fork() machinery.
9e5eb55
Eric Bower
·
2026-07-26
refactor: use posix.zig for all posix fns The zig team is planning to completely kill std.posix so we might as well get ahead of it and bring everything we need into zmx.
4232d74
Eric Bower
·
2026-07-23
refactor: upgrade to zig v0.16.0 The biggest challenge was the deprecation of std.posix. In an effort to upgrade to 0.16 without a major rewrite I decided to port the functions from std.posix that we were heavily using. We can continue to chip away at some of the posix functions but it's likely many will remain until std.Io matures and we can migrate off of using `poll(2)` directly. Build is passing, tests are passing.
93cd148
Eric Bower
·
2026-07-23
fix: improve ci script build times
06c472d
Eric Bower
·
2026-07-23
fix: ci release script
d221e86
Eric Bower
·
2026-07-23
chore: update zmx to v0.7.0
9bcc7bc
Eric Bower
·
2026-07-23
docs: prep v0.7.0
8ba312d
凡辞
·
2026-07-22
fix(send): preserve client leadership
935c484
Siva Mahadevan
·
2026-07-23
build: canonicalize ghostty dep URL (#206) While here, only import build.zig.zon once in build.zig.
3817645
Martin Häcker
·
2026-07-22
Add nix installation instructions (#203)
fa80e7a
Eric Bower
·
2026-07-22
docs: changelog
94d0675
Simon Labrecque
·
2026-04-27
fix(attach): reclaim leader on kitty keyboard input When a non-leader client sends keyboard input like: - `\x1b[102;1:1u` - `\x1b[57444;1:1u` libghostty warns and does not classify the sequence as user input. As a result, handleInput() treats the payload as non-user input and refuses to transfer leadership to the active client. In practice, that leaves a re-attached client unable to take control even though its input is reaching the daemon.
d3b01c7
MyeongjunKim
·
2026-04-08
fix(attach): detect ctrl+\ encoded by xterm modifyOtherKeys PR #92 made the ctrl+\ matcher handle the kitty CSI u encoding. The older xterm modifyOtherKeys encoding (CSI 27 ; mod ; key ~) was still missed, which broke detach when the inner program (e.g. claude) enables modifyOtherKeys level 2 and the outer terminal honors it (e.g. iTerm2). Add a separate matcher mirroring keypressWithMod, with the same lock modifier tolerance. Also force modifyOtherKeys back to level 0 in the detach restore sequence; xterm modifyOtherKeys has no push/pop, so this is unconditional, mirroring the existing unconditional disables for mouse modes, bracketed paste, focus events, and alt screen. Without it the outer shell ends up encoding ctrl combos as escape sequences after detach, corrupting input at the prompt.
5778a84
Eric Bower
·
2026-07-22
docs: readme
61e5cb2
Zixuan Song
·
2026-07-22
doc: add alternative gentle-hint pattern for server SSH workflow (#175) The existing session-picker docs only show an auto-launch pattern (zmx-select && exit), which forces the picker on every SSH login. This is inconvenient on shared servers where quick commands are common. Add an alternative 'gentle hint' pattern that shows a one-line reminder when sessions exist, without blocking the shell.
4ab0a60
Eric Bower
·
2026-07-22
fix: use BRANCH
93247e9
Chris Rose
·
2026-07-04
fix: avoid statx syscall so zmx runs on pre-4.11 kernels (#186)
zmx crashed with `error: Unexpected` on every invocation on a Synology
DiskStation (Linux 4.4.302). `error.Unexpected` is what Zig's std returns
for an unrecognized errno; here the errno is ENOSYS (38) from the `statx`
syscall, which only exists on Linux >= 4.11.
Two code paths issued statx via Zig std, which calls the raw statx syscall
directly and does not fall back like libc does:
- log.zig: LogSystem.init() called file.getEndPos() -> File.stat() -> statx.
This runs before command parsing, so it broke *every* subcommand, not
just attach.
- socket.zig: sessionExists() called Dir.statFile() -> statx.
Both now use fd/at-based stat instead:
- LogSystem.init() uses posix.fstat(file.handle).
- sessionExists() uses posix.fstatatZ() + S.ISSOCK().
Because zmx links musl, these resolve to SYS_fstat / SYS_fstatat (musl on
x86_64 skips statx entirely), which are available on 4.4. Verified by
disassembling the release binary: no reachable statx call remains on the
attach path (the only residual references are the DWARF stack-trace
unwinder and sendFile fast-paths, neither of which zmx exercises).
444fa72
Chris Rose
·
2026-07-22
docs: add mise install instructions (#198)
e404ed6
Aaron Bull Schaefer
·
2026-07-22
docs: add zmx-picker to community tools (#199)
22997b7
Eric Bower
·
2026-07-20
fix: ghostty resize fn changes type sig
62e7e56
Eric Bower
·
2026-07-20
docs: readme
7781824
Eric Bower
·
2026-07-20
fix: HyperlinksetOutOfMemory issue This updates libghostty which fixes a SIGABRT from hyperlink rendering. Closes: https://github.com/neurosnap/zmx/issues/182 Reference: https://github.com/ghostty-org/ghostty/pull/13394
8d5e827
Max Rydahl Andersen
·
2026-06-29
feat: session labels Now you can apply ephemeral key-value pairs to a zmx session and see them when running `zmx list`. This allows users to tag sessions with metadata instead of only relying on the session name.
ce52eb7
Eric Bower
·
2026-07-17
fix: flaky bats tests
fbf900c
Noelle Leigh
·
2026-07-04
fix: Add missing commands to completion scripts - Add print, write, wait, and tail to the scripts in src/completions.zig - Add 'nu' to 'zmx completions' completions (0a5a2a9)
d0eb4cd
Eric Bower
·
2026-07-13
chore: use debian
e05515b
Eric Bower
·
2026-07-13
fix: flaky bats tests
feced06
Eric Bower
·
2026-07-13
docs: update changelog
050a330
Kai Fronsdal
·
2026-06-10
fix(kill): release socket before grace sleep so name is reusable `zmx kill X; zmx run X` raced: the daemon's shutdown defer ran handleKill() first and only then closed the listen socket and unlinked the socket file. Two changes: - Reorder the shutdown defer so the listen socket is closed and the socket file unlinked before handleKill()'s 500ms grace period. - Make `zmx kill` synchronous: after sending .Kill, drain-read the connection until EOF. The daemon closes client fds after unlinking the socket file, so when `kill` returns the name is guaranteed free. Avoids a client-side deleteFile, which would race with a fresh session created in between. Adds test/kill_run_race.bats which fails on main and passes here.
fbbc6be
Vladimir Varankin
·
2026-05-20
chore: store logs in XDG_STATE_HOME Previously we were storing logs inside of our socket_dir technically worked but according to the XDG Base Directory Spec it should be stored inside of STATE. > The $XDG_STATE_HOME contains state data that should persist between (application) > restarts, but that is not important or portable enough to the user that it > should be stored in $XDG_DATA_HOME. It may contain: > - actions history (logs, history, recently used files, …) > - current state of the application that can be reused on a restart > (view, layout, open files, undo history, …) Reference: https://specifications.freedesktop.org/basedir/latest/#variables
30a153e
Jonas Lergell
·
2026-07-13
Update zig2nix lock generation (#195)
f7df947
Eric Bower
·
2026-07-11
chore: upgrade libghostty
96a2aea
Martin Häcker
·
2026-07-08
Fix darwin build (#190) This modifies the build so the flake builds correctly on darwin. `nix flake show` still creates an IFD in the zig2nix flake, but that was a problem before and could be solved by setting pname and version in the package - so nothing that got worse with this patch.
6fabec0
Eric Hanchrow
·
2026-06-28
Suggest the `-t` option to ssh ... (#184) ... when running without config.
b9e135f
Arthur Heymans
·
2026-06-28
doc: Add emacs-term-sessions to list of community tools (#170)
7381df3
이영수
·
2026-06-28
fix: forward real terminal pixel size instead of hardcoding 0x0 (#174)
ipc.Resize only carried rows/cols, and getTerminalSize() dropped the
ws_xpixel/ws_ypixel fields read from TIOCGWINSZ. The daemon's three
TIOCSWINSZ call sites (spawnPty, handleInit, handleResize) then hardcoded
ws_xpixel/ws_ypixel to 0 on the inner pty, regardless of what the real
terminal reported.
This breaks Kitty graphics-protocol image sizing for anything running
inside a zmx session, since image dimensions in cells get computed from
a pixel-per-cell ratio that is always 0. nvim plugins like snacks.nvim
report `{cell}: 0 x 0 pixels` and scale images to nothing before sending
them to the terminal.
Add xpixel/ypixel to ipc.Resize, populate them from the real
ioctl(TIOCGWINSZ) result on the client side, and thread them through to
the daemon's TIOCSWINSZ calls instead of hardcoding 0.
4e2d02b
Simon Hartcher
·
2026-06-28
fix: build ghostty as libghostty-vt only to drop iOS SDK requirement (#181)
zmx only needs the ghostty-vt module, but b.dependency("ghostty", ...)
runs ghostty's full build(), which constructs an XCFramework and resolves
the iOS SDK at configure time via LibCInstallation.findNative. That fails
on machines with only the Command Line Tools installed (no iOS SDK), with
error.DarwinSdkNotFound.
Pass emit-lib-vt=true and emit-xcframework=false at all three ghostty
dependency call sites so ghostty builds the VT library only and skips the
macOS app / iOS XCFramework graph. emit-xcframework must be forced off
because in lib-vt mode it defaults to whether xcodebuild is on PATH, which
is true even with the (non-functional) Command Line Tools stub.
4c2924c
Eric Bower
·
2026-06-19
perf: reduce allocations in the hot-path of the pty-proxy
79169a0
Eric Bower
·
2026-06-12
chore(ci): upload static site on main
af94b80
Eric Bower
·
2026-06-13
chore(ci): generate homebrew file
609f4e3
Scott Abernethy
·
2026-06-18
fix(docs): correct zmx-select field parsing in session picker (#172) The zmx-select snippet stripped field prefixes (session_name=, started_in=) that don't match the actual `zmx list` output, so the session name displayed as "name=test" instead of "test" and attach failed. Use glob strips (#*name=, #*start_dir=) which match the real prefixes and also swallow the leading "→ "/" " current-session marker. Fixes #153 Co-authored-by: freqyfreqy <freqyfreqy@users.noreply.github.com>
df2a09b
Mirri
·
2026-06-18
update README.md for readability (#173)
ba77064
Eric Bower
·
2026-06-12
fix: dev should use_lld only for linux builds
d469b2e
Eric Bower
·
2026-06-12
chore(ci): cleanup
d4d5f2a
Eric Bower
·
2026-05-31
fix(ci): step misconfigurations
364b6a6
Eric Bower
·
2026-05-29
docs: changelog
769334b
Eric Bower
·
2026-05-26
chore(ci): dockerizing main release steps
adb11d6
Eric Bower
·
2026-05-21
refactor: strip ansi escape codes for tail cmd refactor: pass program env vars to help prevent
a25e2fe
Eric Bower
·
2026-05-20
refactor(run): marker for heredoc For most commands we can append `; $?` except for heredoc where the marker needs to be on its own line.
d5c6926
Eric Bower
·
2026-06-12
docs: nu completions
b0ae9d6
Eric Bower
·
2026-06-12
docs: zmx version
2e2b64b
Eric Bower
·
2026-06-12
docs: help cmd
94738e5
Eric Bower
·
2026-06-12
docs: readme
ce66992
Jonas Lergell
·
2026-06-01
fix(run): resolve task bash from PATH (#164)
9889a13
Eric Bower
·
2026-05-20
fix(run): exit marker formatting cleanup
d588268
Eric Bower
·
2026-05-20
refactor(run): when creating session will always run `/bin/bash` BREAKING CHANGE: `zmx run` now requires the target shell to support `$?` exit status tracking
bcf57a1
Eric Bower
·
2026-05-20
fix: zig build linker error References: https://codeberg.org/ziglang/zig/issues/31272
8f1b215
Eric Bower
·
2026-05-16
docs: update version links
6084a4e
Eric Bower
·
2026-05-16
chore: update zmx version v0.6.0
e023199
Eric Bower
·
2026-05-16
fix: needs to build on mac as well
34446b7
Eric Bower
·
2026-05-16
docs: changelog
678a0e3
Eric Bower
·
2026-05-11
chore: add zls to mise
0ba19cd
Amir B.
·
2026-05-16
fix: handle run help flag (#152) Extends the --help/-h check to all subcommands that accept a session name or other positional args, so users don't accidentally create a session named "--help" or trigger confusing errors. Covers: list, completions, history, attach, send, print, write, kill, wait, tail.
a28c87a
Eric Bower
·
2026-05-16
chore: set default width to 160 This is mainly so `zmx run` + `zmx history` isn't so truncated
0f94881
Eric Bower
·
2026-05-16
chore(wait): when looping tasks only print the non-completed tasks
e2a707a
Eric Bower
·
2026-05-16
chore(wait): continue polling every 1s but only print waiting status every 5s
9d1e6dd
Eric Bower
·
2026-05-16
feat(wait): print last 20 lines of session history on failure
936c1fa
Eric Bower
·
2026-05-16
fix: statically link against musl
0a5a2a9
Benjamin Pollack
·
2026-05-12
feat(completions): add nushell
250c980
Eric Bower
·
2026-05-16
fix: mise polluting workspace ci runs
cbb53d5
Eric Bower
·
2026-05-16
fix(ci): dont volume mount the pwd so we can remove mise
04d0b00
Eric Bower
·
2026-05-16
chore: delete mise so it doesn't bomb from not `mise trust` in tmp workspace
5d7aadc
Eric Bower
·
2026-05-09
feat: pico.sh ci integration
7ef2be4
bitbloxhub
·
2026-05-12
fix(nix): update zig2nix so that zmx builds on Lix (#155)
933bb71
Oleg Tarasov
·
2026-05-11
fix: zsh completion autoload registration (#154)
ca701f8
Justin Su
·
2026-05-03
Remove aliases from fish subcommand completions (#149) Fixes #148 Partially reverts #90
e55ccde
Jonas Lergell
·
2026-05-03
chore: update zig2nix lock generation (#150)
c1c7f7b
Eric Bower
·
2026-04-29
feat(wait): summary of failed tasks and actionable commands to run This simply prints the failed tasks and shows some commands to run to see what went wrong.
0ce812c
Eric Bower
·
2026-04-29
chore: update pico.sh
1b62815
Eric Bower
·
2026-04-28
refactor(attach): reset outer terminal to default state Closes: https://github.com/neurosnap/zmx/issues/106
5389d30
Eric Bower
·
2026-04-26
feat: cross-compile from linux to mac Latest version of libghostty now supports cross-compiling without needing Apple sdk tools.
b79c8c7
Eric Bower
·
2026-04-26
chore: update libghostty
129875f
Radosław Stachowiak
·
2026-04-26
feat: accept ls as list alias to help our muscle memory
50db1df
Eric Bower
·
2026-04-26
docs: copy and changelog
9a33769
Eric Bower
·
2026-04-26
chore: cleanup
085fe3e
Ian Tay
·
2026-04-10
refactor(ipc): freeze Tag wire values; switch via connectSession
e889a18
Ian Tay
·
2026-04-10
fix(daemon): self-pipe signal wakeup + version-tolerant IPC liveness
Self-pipe (idle daemon was deaf to SIGTERM/SIGWINCH):
std.posix.poll loops on .INTR internally (PollError has no Interrupted
member), so the prior `catch error.Interrupted` was unreachable since
8640be51/690487b — signals only "worked" when unrelated I/O woke poll().
Replace with the self-pipe trick: posix.pipe2(.{CLOEXEC,NONBLOCK}), one
wakeSignalPipe handler with errno save/restore, pipe read-end at fixed
poll_fds[2] in both loops; resize/shutdown act in the drain branch.
Removes the now-redundant sigwinch/sigterm atomic flags and collapses
setupSig*Handler into installWakeHandler(sig).
IPC versioning (Option E — decouple liveness from Info shape):
connectSession() does connect-only liveness; 5 of 6 callers (kill,
detach, history, run, attach) switch to it so they survive Info struct
changes. probeSession keeps the Info round-trip for `list`, which now
reports InfoSizeMismatch instead of Unexpected on version skew.
Hygiene: clients_len usize->u64 (extern struct); handleInfo zero-inits
Info so asBytes() doesn't ship 7B tail padding + cmd/cwd stack tails.
Tests freeze @sizeOf(Info)=552 / @sizeOf(Header)=8 and assert zeroed
Info ships zero padding; wired via test{_=ipc;}.
cd82c84
Eric Bower
·
2026-04-25
docs: pi-zmx
c654778
Eric Bower
·
2026-04-25
fix(run): ignore DA queries when no terminal client connected `run` is not a real terminal client, it just tails the output and cannot respond to shell QA queries so we have a special flag that ignores read-only clients
758a137
Eric Bower
·
2026-04-24
refactor(run): check pty foreground process to detect shell This removes the need to provide the `--fish` flag at all for `zmx run` commands.
5ebf61b
Eric Bower
·
2026-04-23
feat: print cmd This sends text directly to client's stdout as-is. Typically you'll want to wrap the text in '\r\n' but we leave that up to the end-user
4164523
Pavel Borzenkov
·
2026-04-24
fix(daemon): reset leader fd on client disconnect (#141)
Make sure leader fd is reset when the leader client disconnects abruptly
without going through 'Detach' IPC. Otherwise, the daemon may remember
wrong client fd as the leader and run all input from the client via
libghostty parser.
Fixes #135
NOTE: this currently doesn't address the issue when libghostty can't
parse the byte sequence and complains like this:
[warning] (parser): CSI colon or mixed separators only allowed for 'm'
command, got: terminal.Parser.Action{ .csi_dispatch = .{ .intermediates
= { }, .params = { 57444, 1, 1 }, .params_sep = .{ .mask = 2 }, .final
= 117 } }
6feca74
Jay Botte
·
2026-04-21
feat: send raw bytes to pty input This is a wrapper around the `.Input` event. Send delivers bytes to the PTY exactly as-is with no automatic carriage return. The caller is responsible for appending \r when shell command submission is desired.
3750464
Eric Bower
·
2026-04-21
feat: zig build test-integration
c6f3ccb
Eric Bower
·
2026-04-21
chore: remove debug test file
6e07f1a
Eric Bower
·
2026-04-21
chore: add zig to mise toml
b18b8f7
Eric Bower
·
2026-04-21
refactor(test): use `run -d` in tests and detect shell
d63cf5b
x1f9
·
2026-04-02
test: add BATS session lifecycle tests and mise.toml 14 tests covering session creation, listing, killing, history, wait, ZMX_DIR isolation, and rapid churn. These tests create real daemon processes — without the inherited-FD close fix, every test that calls `zmx run` would hang indefinitely. mise.toml declares bats 1.13.0 as a dev dependency, establishing the pattern for managing project tooling.
e70e8b2
x1f9
·
2026-04-02
fix(daemon): redirect stdio to /dev/null after fork The existing FD close loop (3-63) handles bats' internal file descriptors, but bats' `run` keyword captures output via pipes on FDs 0-2. The daemon inherits these pipe write ends and holds them open, so bats never gets EOF and hangs. Redirect stdin/stdout/stderr to /dev/null right after setsid(). The daemon communicates exclusively via its unix socket — it never reads stdin or writes stdout/stderr. This is standard daemon hygiene and completes the inherited-FD fix.
efd35ac
ikma
·
2026-03-28
fix(daemon): close inherited file descriptors after fork After the daemon forks and re-initializes its own log file, close all file descriptors from 3 to 63 (excluding server_sock_fd). These FDs are inherited from the parent process and are not needed by the daemon. Without this fix, test harnesses like bats hang indefinitely. Bats uses FDs 3+ internally and waits for them to close before exiting. Since zmx forks a long-lived daemon that inherits these FDs, bats never sees them close and blocks forever. The close happens after log_system.deinit()/init() to avoid closing the parent's log FD before it's properly released, and before spawnPty() so the PTY FD (allocated after this point) is not affected. Uses std.c.close() (raw libc) instead of std.posix.close() to avoid panicking on already-closed or invalid FDs.
a74702a
Eric Bower
·
2026-04-21
style: index page
81243b9
Yi Zhou
·
2026-04-16
Update fish completions for zmx v0.5.0 (#134)
66d1b8b
Eric Bower
·
2026-04-16
style: site change
5a761ab
Eric Bower
·
2026-04-16
docs(readme): copy
9d01661
Eric Bower
·
2026-04-16
chore: prep for v0.5.0
87dc8d1
Eric Bower
·
2026-04-16
fix: default to bash when running command
24305c0
Eric Bower
·
2026-04-16
fix(write): remove bracketed paste Some shell environments don't support it and we are only sending 1 line at a time so we should be okay to remove it.
12d7505
Eric Bower
·
2026-04-16
docs: copy and cleanup
7ce50ee
Eric Bower
·
2026-04-14
fix: add logo back
096ab1d
Eric Bower
·
2026-04-14
refactor: doc site
911f789
Eric Bower
·
2026-04-14
docs(readme): paste help msg
538ed39
Eric Bower
·
2026-04-14
docs: changelog updates
3a901e0
Eric Bower
·
2026-04-14
refactor: require "*" suffix for wildcard matches This applies to: wait, kill, and tail Examples: - zmx wait "dev*" - zmx kill "dev*" - zmx tail "dev*" - zmx kill "*"
e719274
Eric Bower
·
2026-04-10
feat: tail, write, and run -d I'm calling this the ai portal integration. These features allow a local code agent to be fully operational against a zmx session that is remote. Everything works by sending key strokes directly into the zmx session. This means it doesn't matter where the remote session lives it should work as if you were typing the commands yourself. SSH'd into a server? Inside a container? It's all the same to zmx and the code agent. BREAKING CHANGE: `zmx run` is now synchronous by default *and* immediately tails the session output so the agent can get immediate feedback. To use the previous run behavior where the run command completes immediately use detached mode: `zmx run -d`
bbbe245
Shravan Sunder
·
2026-04-14
fix: rewrite OSC 133;A with redraw=0 to prevent prompt loss on resize (#112) When zmx forwards shell output containing OSC 133;A (prompt start) to the outer terminal, the terminal sets shell_redraws_prompt=true. On resize, the terminal clears prompt rows expecting the shell to redraw them. But the shell's redraw goes through zmx's IPC relay chain with cursor coordinates relative to the inner PTY state, causing a cursor desync that makes the prompt invisible. Fix: rewrite OSC 133;A to include redraw=0 before forwarding. This tells the outer terminal that the process on its PTY (zmx client) cannot redraw prompts, so it should leave prompt rows intact on resize. This is a standard Kitty protocol extension. Also disables shell_redraws_prompt on the daemon's internal ghostty_vt terminal during resize to prevent snapshot state corruption. Fixes #111. Likely also fixes #99.
6eea0f6
Eric Bower
·
2026-04-12
chore: dont show task_command because it is unreliable We just don't have a great way to send [][]u8 over ipc because we are using structs with fixed size fields that are converted to/from via std.mem.asBytes. This means we have to convert the command from [][]u8 to []u8 but that makes our daemon struct fields complicated. Instead, just rely on looking at the zmx history to understand the command that was run.
fbf0171
Adrian
·
2026-04-13
feat: allow configuring socket and log permissions via environment variables (#130)
5f30ba8
Eric Bower
·
2026-04-09
docs(readme): demo video
b610ddd
Eric Bower
·
2026-04-09
refactor: set leader by detecting user input with libghostty parser
af0e1f3
Eric Bower
·
2026-04-08
chore: cleanup util formatting
3971f2d
Michael Sakaluk
·
2026-03-18
fix: two-phase terminal state serialization for nested session cursor corruption Fixes #31 (cursor position corruption on re-attach over SSH). Partially addresses #86 (cursor style error after attach). Contributes to #96 (testing framework). Problem: When running nested zmx sessions (zmx→SSH→zmx), re-attaching to the outer session causes cursor positions and screen content to appear at wrong rows. The root cause is that serializeTerminalState() writes scrollback + visible content sequentially. Scrollback lines scroll the terminal before CUP sequences arrive, shifting all visible content by the scrollback overflow. Fix: Split serialization into two phases: 1. Phase 1: Emit scrollback content only (no modes/cursor/keyboard). These lines scroll into the terminal's scrollback buffer. 2. Clear visible screen (ESC[2J ESC[H ESC[0m) to reset for phase 2. 3. Phase 2: Emit visible screen only with full extras (modes, cursor, keyboard, scrolling region). The clear between phases ensures visible content starts from a clean slate regardless of how much scrollback preceded it. Scrollback is preserved in the terminal's buffer for native scroll-up. This approach is inspired by tmux's visible-only redraw strategy but preserves terminal scrollback. Tests: Added 7 integration tests using ghostty-vt roundtrip verification: - Cursor position preservation after roundtrip - CUP-positioned markers survive roundtrip - Scrollback does not shift visible content (the core bug) - Nested double-roundtrip (inner→outer→client) - Alternate screen content not leaked - Terminal size mismatch (30→24 rows) + roundtrip - Scrollback + size mismatch + nested roundtrip (stress test) All tests run in <1 second via `zig build test`.
3df5416
Eric Bower
·
2026-04-08
docs(changelog): switching sessions
99c40d3
Eric Bower
·
2026-04-08
chore: use env var fn for session name
43e6f0f
Eric Bower
·
2026-04-03
feat(attach): support switching sessions Previously we did not allow users to switch to a session from within a session via `zmx attach`. Now users are able to run `zmx attach` from within a session and it'll properly detach and then reattach to the new session. References: https://github.com/neurosnap/zmx/issues/91
66c8e0e
Eric Bower
·
2026-04-08
feat: change pty window size when new leader is set When we set a new client leader we send a Resize event request from the daemon to the client. So now whenever a user types into their stdin we set the new leader and then resize the window.
bdbf795
Eric Bower
·
2026-04-05
chore(leader): init cmd only resize if leader
87f89de
Eric Bower
·
2026-04-04
fix: kitty up arrow detection
c6956f8
Eric Bower
·
2026-04-04
chore(leader): up arrow can claim client leader
a65e500
Eric Bower
·
2026-04-04
fix(util): tests
08a06c0
Eric Bower
·
2026-04-04
refactor: kitty key press logic to be more generic fix: src/util.zig tests were not being run :sad:
d0e3ed1
Eric Bower
·
2026-04-03
refactor: generic parsing kitty ctrl key fns
e9729b9
Eric Bower
·
2026-04-03
docs: leader comment
d48b642
Eric Bower
·
2026-04-03
feat: new client leader policy The last client to send user input bytes (non-ansi escape codes) becomes the leader. The client leader controls resizing and any other terminal state changes. Non-leader clients are read-only until they send user input bytes and takeover leadership. Closes: https://github.com/neurosnap/zmx/issues/73
77d03a5
Eric Bower
·
2026-04-02
feat(kill): add `--force` flag to remove the socket file If we cannot communicate with the daemon then it could mean a number of things. We don't automatically assume that a communication error means we can never connect to it. So we add a `--force` command for when there is an error the user cannot recover from and we will delete the socket file. Unfortunately, we do not know the pid for the terminal session outside of the daemon so we cannot automatically kill the pid in some cases which means it could linger.
cc33276
とーふとふ
·
2026-03-31
fix(daemon): close pty master before waitpid to prevent zombie on macOS (#114)
1aaf713
Eric Bower
·
2026-03-31
docs(ai): introduce claude skill
3477fb2
Ian Tay
·
2026-03-18
feat(daemon): buffer PTY stdin writes and flush via POLLOUT Replaces the best-effort ptyWrite (drop on EAGAIN) with a buffered queue flushed by the daemon's poll loop. Mirrors the pattern already used for client-socket writes. - pty_write_buf on Daemon, capped at 256KB (drop new payload on overflow — same failure mode as before, 64x higher threshold) - POLLOUT registered on pty_fd when buffer non-empty; flush handler loops until EAGAIN - handleInput/handleRun queue instead of writing directly - respondToDeviceAttributes routes through the same buffer so DA responses can't interleave with a draining .Run payload after client disconnect Follow-up to #82.
98fa966
Eric Bower
·
2026-03-23
feat(kill): accepts multiple args and matches session prefixes Examples: - zmx kill one - zmx kill one two three - zmx kill d. - ZMX_SESSION_PREFIX="d." zmx kill
fac9795
Eric Bower
·
2026-03-23
chore: dockerfile and ci file I'm experimenting with using zmx as a job engine for CI.
7cdb333
Eric Bower
·
2026-03-23
chore: wrap lines where applicable to 100
4dff5d4
Eric Bower
·
2026-03-23
docs: index file
932e0ed
Eric Bower
·
2026-03-23
docs: cleanup and rewording I'm removing `AGENTS.md` mainly because it is not particularly useful and there is research to suggest these files don't really improve agent performance.
3b0e4e8
Eric Bower
·
2026-03-22
docs: doc strings
89e2728
Eric Bower
·
2026-03-22
fix(list): send no session found msg to stderr Fixes: https://github.com/neurosnap/zmx/issues/101
7785934
Eric Bower
·
2026-03-19
chore: detach key cleanup
a9dc983
Patrik Sundberg
·
2026-03-17
fix(attach): reject combined intentional modifiers for Ctrl+\ detach The parser accepted any modifier combination that included ctrl (ctrl+shift, ctrl+alt, ctrl+super, etc.) because it only checked the ctrl bit. This was over-permissive: ctrl+shift+\ is a different key combination and should not trigger detach. Tighten the check to require ctrl as the ONLY intentional modifier. Lock modifiers (caps_lock, num_lock) remain tolerated since they are ambient state, not deliberate key combinations.
46b02ee
Patrik Sundberg
·
2026-03-15
fix(attach): handle all kitty keyboard protocol encodings for Ctrl+\ The old detection used rigid substring matching for exactly two sequences (\x1b[92;5u and \x1b[92;5:1u). This failed when apps enabled progressive enhancement flags that change the encoding: - Lock modifiers (caps_lock, num_lock) alter the modifier value - Alternate key sub-fields add :shifted:base after the key code - Combined modifiers (ctrl+shift, ctrl+alt, etc.) change the value - Text codepoint sections append an extra ;codepoints field Replace with a proper CSI u parser that: 1. Matches key code 92 (backslash) with any alternate sub-fields 2. Checks the ctrl bit in the modifier value: (mod - 1) & 0b100 3. Accepts press/repeat events, rejects release 4. Tolerates optional text codepoint sections
a0c915c
Eric Bower
·
2026-03-19
docs(readme): mark as unofficial packages
48d9a17
Vishal
·
2026-03-19
fix: avoid replaying synchronized output on reattach (#95)
27bd9b8
Eric Bower
·
2026-03-18
chore: prep for 0.4.2 release
19d1b76
Samuel Hautamäki
·
2026-03-17
Document the new Gentoo overlay. (#94)
1065bfd
Eric Bower
·
2026-03-13
refactor: move print fn to socket.zig
fb0e621
Michael Sakaluk
·
2026-03-10
fix: validate session name length against Unix socket path limit Session names that cause the socket path to exceed the OS sun_path limit (104 bytes on macOS, 108 on Linux) now produce a clear error message instead of failing silently with exit code 1. - Add max_socket_path_len constant derived from platform sockaddr_un - Add validation in getSocketPath returning error.NameTooLong - Add maxSessionNameLen helper for dynamic limit computation - Add printSessionNameTooLong for user-facing error on stderr - Handle NameTooLong in all command paths (run, attach, kill, history, detach, list) - Move validation before sessionExists in kill/history so the error message is shown even when the socket file doesn't exist - Add 6 unit tests covering boundary conditions and platform constants Fixes: https://github.com/neurosnap/zmx/issues/84
f520c4c
Yi Zhou
·
2026-03-12
Refactor fish completions for zmx command (#90)
fd29a10
Iván Hernández Cazorla
·
2026-03-12
chore: add openSUSE package link to website (#89)
ecf3857
Michael Sakaluk
·
2026-03-12
fix: print error to stderr when session does not exist (#88)
49b126a
Eric Bower
·
2026-03-11
fix(attach): type error
d0683a3
Eric Bower
·
2026-03-11
chore(history): bare `zmx history` should try to use `ZMX_SESSION`
1fc6306
Ian Tay
·
2026-03-08
fix(ipc): validate wire data before arithmetic and indexing - expectedLength: header.len is u32 off the wire; adding sizeof(Header) at u32 width could wrap (panic in safe mode, UB slice bounds in release). Widen to usize first. - get_session_entries: cmd_len/cwd_len are u16 (max 65535) but index into [256]u8 arrays. Clamp before slicing.
df38b13
Ian Tay
·
2026-03-08
fix(attach): skip termios setup when stdin is not a TTY tcgetattr's return value was discarded, so when stdin was piped (e.g. `zmx attach foo < /dev/null`), orig_termios remained Zig `undefined` stack bytes. These garbage bytes were then copied, modified by cfmakeraw, and applied via tcsetattr — UB in safe builds.
4a6604b
Ian Tay
·
2026-03-08
fix(attach): serialize terminal state before resize, as the comment says The existing comment correctly explains why serialize must happen before resize (reflow moves the cursor), but the code did the opposite. Reattaching with a different terminal size could leave the cursor misplaced.
76cec40
Ian Tay
·
2026-03-08
fix(pty): isolate forked child from parent code path and heap-alloc argv Two issues in spawnPty's child (pid==0) branch: 1. `try` on allocPrint/bufPrintZ could propagate an error past the if-block, causing the forked child to fall through to the parent code path — running a second daemon on the same socket, or hitting errdefers that delete the parent's socket file. The bufPrintZ case is triggerable via a long SHELL basename. 2. The fixed-size argv_buf[64] overflowed with >63 CLI arguments. Both are fixed by extracting child setup into execChild() which returns !noreturn (exec or error), with the caller exiting on any error. The argv array is now heap-allocated to the exact size needed.
11a12cc
Ian Tay
·
2026-03-08
fix: only clean up socket on ConnectionRefused, not Timeout A 1-second probe timeout doesn't mean the daemon is dead — it may just be busy (heavy output, terminal resize reflow, serializing state for another client). Deleting a live daemon's socket orphans it permanently with no way to reach it via zmx commands. Applied to all callsites: get_session_entries, ensureSession (worst case: spawns a replacement daemon leaving the old one orphaned), kill, detachAll, history. For kill, the user now gets a helpful message if the daemon is busy vs. actually dead. The `zmx list` status label for error entries now says `status=unreachable` (not `cleaning up`) on Timeout, so the display doesn't contradict what we actually did. `zmx wait` now treats is_error entries as done+failed: on Timeout the socket persists, so without this the session would sit at task_ended_at==0 forever, defeating both the completion check and the zero-match timeout.
690487b
Ian Tay
·
2026-03-08
fix: signal handling — ignore SIGPIPE, handle EINTR in poll - Ignore SIGPIPE once in main() (inherited across fork, covers all subcommands). Without this, writing to a closed socket delivers SIGPIPE (default disposition: terminate) before write() can return EPIPE. An abrupt client exit killed the daemon; a daemon that died between probe and send killed one-shot clients (run/kill/history). - Handle EINTR in the daemon's poll loop (clientLoop already does this). Without this, SIGTERM/SIGCHLD caused the daemon to exit with an error instead of checking the sigterm flag and shutting down gracefully. Note: SA_RESTART is intentionally NOT set on SIGTERM/SIGWINCH. On BSD/macOS (unlike Linux), poll() is restartable when SA_RESTART is set — an idle daemon would never wake from poll() to check the sigterm flag. The EINTR handling in the poll loop is the correct and sufficient fix.
12a19ee
Ian Tay
·
2026-03-08
fix: use platform-correct O_NONBLOCK for fcntl; fix PTY write and double-close The hardcoded value 0o4000 is Linux-specific; on macOS O_NONBLOCK is 0x4. posix.SOCK.NONBLOCK is for socket()/accept4(), not fcntl(F_SETFL) — it only worked on Linux by coincidence where both constants share the same value. On macOS, non-blocking mode was never actually set on the PTY, client socket, or stdin. Setting O_NONBLOCK correctly exposes two latent issues, also fixed here: - PTY writes in handleInput/handleRun did `_ = try posix.write()`, discarding short-write counts and propagating WouldBlock as an error that crashed the daemon. Added ptyWriteAll() that polls on WouldBlock and retries short writes — same blocking semantics macOS had implicitly. - ensureSession's errdefer + defer both closed server_sock_fd when daemonLoop errored, causing EBADF (posix.close treats this as unreachable → panic in safe builds). Restructured so spawnPty failure is handled by an explicit catch; the defer is the sole owner after. Additionally, O_NONBLOCK is set on the open file description (shared with the parent shell), so stdin's original flags must be restored on exit to avoid leaving the parent shell's stdin in non-blocking mode.
35f56e6
Ian Tay
·
2026-03-08
fix(wait): time out after 3 polls if no matching sessions are found Follow-up to the upstream wait fix: the `total > 0` guard prevented vacuous exit 0, but left a typo'd `zmx wait foo` polling forever — trading a wrong answer for no answer. After 3 iterations (~3s) with max_seen still at 0, exit 2 with "no matching sessions found". 3s is generous: `zmx run foo && zmx wait foo` is essentially sequential (run blocks until the socket exists and the Run IPC is acked), so a persistent zero is a typo, not slowness.
2d37a09
Iván Hernández Cazorla
·
2026-03-08
chore: add link to openSUSE Tumbleweed package (#79)
a27b371
Ian
·
2026-03-08
Fix verified bugs (#83) * fix: validate session names to prevent path traversal Session names become filenames under socket_dir. Without validation, `zmx attach ../foo` would create a socket outside that directory, and (worse) stale-socket cleanup via unlinkat(dirfd, "../foo") would delete files outside it. The ZMX_SESSION_PREFIX env var was similarly unsanitized. Also fixes a minor inefficiency: seshPrefix() was called twice. * fix(history): don't panic when only flags are provided `zmx history --vt` panicked on the .? unwrap when no positional session name was given. Pass empty string instead so getSeshName handles it (returns error.SessionNameRequired if no ZMX_SESSION_PREFIX is set either). * fix(wait): don't report vacuous success when no sessions match total == done was true when both were 0, so `zmx wait foo` returned exit 0 immediately if no session named foo existed — either because of a typo, or because of a race where the preceding `zmx run foo` hadn't yet created its socket. Now wait keeps polling until at least one matching session is seen. Also tracks the high-water mark of matched sessions: if the count drops, a session disappeared (daemon crashed or was killed), so wait errors out instead of looping forever. * fix(run): reset task state when receiving a Run command The daemon's exit-marker scan is gated on task_exit_code == null, but that field was never reset after the first task completed. A second `zmx run` on the same session would have its ZMX_TASK_COMPLETED marker ignored, causing `zmx wait` to immediately return the *first* task's exit code. Also explicitly set is_task_mode so `zmx run` works against sessions that were originally created by `zmx attach` (non-task mode). * fix(run): use CR not LF to submit commands to an already-prompting shell When `zmx run` sends a command to an existing session, the shell is at the readline prompt with the PTY in raw mode. readline binds accept-line to CR (\r), not LF (\n), so a trailing \n just moves the cursor — the command sits typed but unexecuted. The first-ever `zmx run` on a fresh session happened to work because it's sent during shell startup, before readline takes over: the line discipline is still canonical and ICRNL translates \n. Any subsequent run silently did nothing, which was masked by the stale-task-state bug (wait returned the first run's exit code, looking like success). \r works in both modes: canonical mode translates it via ICRNL, and raw-mode readline accepts it directly.
ccdc1b9
Danil Agafonov
·
2026-03-06
docs: add session picker recipe using fzf (#75) Add a shell function that fuzzy-finds and attaches to zmx sessions, previews scrollback history, or creates new ones. Includes a Ctrl-N keybinding to force session creation when a fuzzy match is highlighted. Particularly useful for remote SSH workflows.
0222428
Eric Bower
·
2026-03-04
refactor: break up main.zig This is just some code cleanup to make it a little easier to navigate the codebase. I don't want to break everything up into separate files but I want the main business logic to live inside of main.zig.
fe2c4ce
Eric Bower
·
2026-03-04
chore: remove comment about old strat
fix(run): always single-quote args to avoid bash history expansion bug The previous shellQuote preferred double quotes, but \! does not suppress history expansion inside double quotes in interactive bash. Switch to always using single quotes (matching Python's shlex.quote), which are universally safe since nothing is special inside single quotes except ' itself. Add unit tests for shellNeedsQuoting and shellQuote. Fixes #72 Made-with: Cursor
b2833e7
Eric Bower
·
2026-03-03
chore(list): changed key names and made formatting more stable
be4cb72
Eric Bower
·
2026-03-03
docs: changelog
87cc98f
Eric Bower
·
2026-03-03
fix(run): stdin regression with ZMX_TASK_COMPLETED We were not actually running the command sent into stdin properly. Closes: https://github.com/neurosnap/zmx/issues/71
d12b7cc
Eric Bower
·
2026-03-03
fix(run): when no client is attached, send DA response query from daemon
954f8db
Eric Bower
·
2026-03-03
fix(run): re-quote when using shell meta chars argv doesn't receive the quotes in the command line so we need to apply an algorithm to re-quote args when it uses special meta-characters. Closes: https://github.com/neurosnap/zmx/issues/72
ac857cf
rok
·
2026-03-01
fix: fix nix build failure (#69)
73aa243
Eric Bower
·
2026-02-28
fix(wait): use-after-free
804e4e2
Justin Su
·
2026-02-27
Use `env_var` module in Starship prompt snippet (#66)
1e4e888
ida
·
2026-02-26
Add starship shell prompt instructions (#62)
954b392
Justin Su
·
2026-02-26
Update fish shell instructions to use user completions directory (#64)
a060a8e
Justin Su
·
2026-02-26
Simplify `brew tap` and `brew install` into a single command (#65)
728beaa
Eric Bower
·
2026-02-23
chore: publish v0.4.1
09b69c2
Eric Bower
·
2026-02-23
fix(ghostty): zig build test was failing
1f4d79d
Noelle Leigh
·
2026-02-22
docs: Fix typo in CHANGELOG "stale" → "stall" Signed-off-by: Noelle Leigh <noelle_leigh@fastmail.com>
f783c17
Eric Bower
·
2026-02-22
docs: add alpine pkg
694699e
Eric Bower
·
2026-02-22
docs: site
103b62b
Eric Bower
·
2026-02-22
docs: readme new install.packages section
9db69ec
L.B.R.
·
2026-02-21
fix(terminal): pop Kitty keyboard protocol on detach (#59)
48520f9
Eric Bower
·
2026-02-20
docs: readme
5ae3cfb
Eric Bower
·
2026-02-20
chore: publish v0.4.0
fc848b0
Eric Bower
·
2026-02-20
chore: update libghostty-vt
8cf33e1
Eric Bower
·
2026-02-20
chore: nanoTimestamp -> timestamp
58eb669
Eric Bower
·
2026-02-20
docs: changelog
e5b9dcd
L.B.R.
·
2026-02-20
docs: add zmosh to community tools (#58) Co-authored-by: L.B.R. <lbr@mmonad.com>
894eced
Eric Bower
·
2026-02-20
docs: readme
714641d
Eric Bower
·
2026-02-20
docs: readme
770481a
L.B.R.
·
2026-02-20
fix: add missing fields to writeSessionLine test (#56)
08b33dc
Eric Bower
·
2026-02-19
chore(wait): add `w` alias
595690f
Eric Bower
·
2026-02-19
docs: readme
fd0874e
Eric Bower
·
2026-02-19
feat: wait command This command will wait for all tasks to be completed and return an "aggregate" exit code.
15c4a9c
Eric Bower
·
2026-02-17
feat: env var `ZMX_SESSION_PREFIX` This change will allow users to set an environment variable that prefixes all session names with the value provided in the env var. This should help with some automation tasks relying on zmx since you can now "group" sessions together under a common prefix.
fbcec11
Eric Bower
·
2026-02-08
feat(run): track task completion with a marker and record exit code
969ef90
Eric Bower
·
2026-02-19
docs: readme
66c7fa1
Eric Bower
·
2026-02-19
docs: readme
9b3b44a
Michael Sakaluk
·
2026-02-19
docs: add zsm to community tools section in README (#55)
5663cb9
Eric Bower
·
2026-02-18
chore: new logo
75bd1b4
Eric Bower
·
2026-02-18
chore: new logo
e3f5d96
Eric Bower
·
2026-02-16
feat(version): print socket and log directory locations
e21e726
wegel
·
2026-02-12
chore: update ghostty to HEAD (#53)
7a30c62
David Calhoun
·
2026-02-02
docs: Fix typo in feature list on index.html (#51)
bc17397
Eric Bower
·
2026-02-01
docs: readme
0dae6cf
Eric Bower
·
2026-02-01
chore: publish v0.3.0
98995bd
Eric Bower
·
2026-02-01
chore: short should be session name only
79fce5d
Paul Smith
·
2026-01-24
feat: indicate current session in listing This change adds a visual indicator (a prefixed arrow) of the current session, if any, to session listings with `zmx [l]ist`. Example: ``` $ zmx l session_name=o.quux pid=38719 clients=0 started_in=/home/example → session_name=o.foo.bash pid=60775 clients=2 started_in=/home/example session_name=o.foo.quux pid=50707 clients=1 started_in=/home/example session_name=o.zmx pid=21531 clients=2 started_in=/home/example session_name=o.zmx.bash pid=17772 clients=1 started_in=/home/example $ zmx l --short o.quux → o.foo.bash o.foo.quux o.zmx o.zmx.bash ``` If there is no current session, the output is unchanged. Fixes #42.
a32b80d
Eric Bower
·
2026-01-23
docs: completions check if cmd exists first
b2fc56b
Eric Bower
·
2026-01-23
docs: copy
f062076
Josh Bainbridge
·
2026-01-01
docs: add documentation for evaluating auto-complete After adding support for auto-completion, we could add instructions for users on how to integrate this into their shell configurations. Update the README with a new sections for shell auto-complete configuration.
3e5f982
Josh Bainbridge
·
2026-01-01
feat: add completions command to output shell completion scripts Adding auto-completion support for a limited number of commonly used shells (bash, zsh, fish) would allow for greater shell integration. This can be done by using completions command that is then evaluated in the shell config. Add a new completions module that holds completion scripts for zsh, bash and fish. Then include a new command called completions that takes a shell name and outputs the requested script. This can then be added to a shell config such as .zshrc like so: eval “$(zmx completions zsh)" For automatic shell integration.
68dfbef
Josh Bainbridge
·
2026-01-01
feat: add new short list option via flag Listing just the session names, without extra information, could be useful for external tools or processes that need to do operations based on the session names. Add a new --short option to the list subcommand to list only session names without extra information.
314974e
Eric Bower
·
2026-01-23
chore(version): show git sha if running dev build
1dbbe3d
Eric Bower
·
2026-01-23
feat(list): show `started_in` directory and original `cmd` if provided
e17899d
Eric Bower
·
2026-01-21
fix: properly handle killing shells and children Shell's typically ignore SIGTERM unless there's a trap installed, but they will respond to SIGHUP. This works fine for shells but when a user runs `zig attach editor nvim` or any other non-shell command they might not respond to SIGHUP the way we want. So we have implemented a multi-signal approach: - SIGHUP - Wait 500ms - SIGKILL Reference: https://github.com/shell-pool/shpool/blob/1b3b27f059f0008c0509b5170d84b86c752b1da3/libshpool/src/daemon/shell.rs#L79-L94 Reference: https://github.com/neurosnap/zmx/pull/47
377c062
Eric Bower
·
2026-01-20
fix: gracefully shutdown daemon process This change properly handles when the daemon process receives a SIGTERM. Also during the kill process we properly forward SIGTERM to all children processes of the daemon.
6e6bc9c
Eric Bower
·
2026-01-09
docs(readme): copy