main
250 commits (250 out of 385 generated)
4c2924c
Eric Bower  ·  2026-06-19
main
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
4d398e8
External.Kai-Fronsdal  ·  2026-03-04
single-quote-escape
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
766fb8a
Eric Bower  ·  2026-01-09
docs(changelog): add recent changes
c597d8d
Eric Bower  ·  2026-01-09
feat(history): add `--vt` and `--html` flag

The `--vt` flag will send the raw ansi escape sequences to recreate the terminal
session.  The idea is that this could be useful for debugging purposes.

The `--html` flag was added because, why not? It's there, might as well
use it.
370157c
Eric Bower  ·  2026-01-08
fix: spawn as login shell

The `-{shell}` convention signals to most shells that they should behave as if invoked as a login
shell, loading appropriate startup files (like .bash_profile or .zprofile).

Reference: https://github.com/neurosnap/zmx/issues/41
e08583b
Eric Bower  ·  2026-01-08
chore: update ghostty to HEAD
18d9fc7
Sebastian Berns  ·  2026-01-07
Add powerlevel10k zsh theme instructions (#40)

16d66af
Eric Bower  ·  2026-01-04
docs(readme): known issue with kitty protocol
a915182
Eric Bower  ·  2026-01-02
fix: use own ghostty vt to test
c01f815
bdillahu  ·  2025-12-30
Update README.md (#36)

6cf1ce6
Eric Bower  ·  2025-12-30
docs(readme): known issues
340de5d
Josh Bainbridge  ·  2025-12-30
docs: add instructions on updating the bash shell prompt (#35)

There are missing instructions on updating the prompt for bash.

Combine both the zsh and the bash instructions in a generic setup.
a061876
Eric Bower  ·  2025-12-29
fix: prevent terminal state corruption on detach

When zmx sessions are nested through SSH (host zmx -> ssh -> remote zmx),
the detach restore sequence was corrupting the outer session's terminal
state tracking in ghostty-vt.

The issue: when the remote zmx client detached, it sent clear screen and
home cursor sequences (\x1b[2J\x1b[H) which flowed through SSH to the
host's PTY. This caused the host's ghostty-vt to update its cursor
position, and since nothing followed to correct it, subsequent reattaches
to the host session would restore with incorrect cursor positioning.

The fix: remove clear screen and home cursor from the detach sequence.
We still reset terminal modes (mouse tracking, bracketed paste, alt
screen, etc.) to ensure the terminal is left in a sane state.

Trade-offs:
- On detach, users now see the session content instead of a cleared
  screen. This is arguably useful feedback showing what was happening.
- Nested zmx through SSH may still have cursor positioning issues since
  the restore's CUP sequence also flows through to the outer session.
  This is accepted as an edge case we cannot fully solve without
  breaking normal operation.
- The attach clear is kept because it provides a clean slate and any
  corruption it causes is immediately overwritten by the session restore.

Design principle: be conservative about terminal escape sequences sent
on detach since they persist and affect the outer terminal's state.
The session restore handles reconstruction, so we don't need to
"clean up" on the way out.

References: https://github.com/neurosnap/zmx/issues/31
543b45c
Eric Bower  ·  2025-12-29
chore: remove trailing slash from TMPDIR
8809f7e
Eric Bower  ·  2025-12-29
chore: publish v0.2.0
59cbc53
Eric Bower  ·  2025-12-29
docs(readme): debugging section copy
cb35332
Eric Bower  ·  2025-12-28
feat: `zmx [r]un` to send a command to a session without attaching to it
0a8bd81
Eric Bower  ·  2025-12-28
docs: readme
927bc64
Eric Bower  ·  2025-12-27
refactor: remove ctrl+b + d detach shortcut

This feature was annoying to implement because we can't simply check for
a single byte, we first have to detect if ctrl+b was pressed then check
for d.

In the end I don't like the complexity it introduces and it seems pretty low
value since we should recommend users simply close their terminal
window.
dce3f04
Eric Bower  ·  2025-12-27
docs: dont advertise alternative shortcut yet

I might remove this shortcut since i'm noticing issues.
3c26522
Eric Bower  ·  2025-12-27
feat: `zmx [hi]story` command which prints session scrollback as text
ceb43cc
Eric Bower  ·  2025-12-24
refactor: make client socket write non-blocking
9e8f01e
Eric Bower  ·  2025-12-22
fix: first attach, resize first
b8c162e
Eric Bower  ·  2025-12-20
fix: timing issue with first attach and sending terminal state

On first attach we don't want to send the terminal state but there
appears to be a timing issue where sometimes we already have pty output
before the Init handler can complete.
3018787
Eric Bower  ·  2025-12-19
docs: update changelog
cfe70f6
Eric Bower  ·  2025-12-19
fix: correct cursor position when reattaching to session

Serialize terminal state BEFORE resizing the terminal in handleInit.
Previously, the resize was done first, which caused cursor reflow and
moved the cursor position. The shell's SIGWINCH-triggered prompt redraw
would then run after our snapshot was sent, leaving the cursor at the
wrong position (end of line instead of after the prompt).

By capturing the terminal state before resize, we preserve the correct
cursor position from when the user detached.
2b8ec0f
Eric Bower  ·  2025-12-19
docs: update detach key
3dcce3d
Eric Bower  ·  2025-12-19
refactor: input shortcut handling

Another code clarity change that abstracts handling the shortcuts for
detach
f15dee4
Eric Bower  ·  2025-12-19
refactor: daemonLoop and terminal serialization

Code cleanup to make the daemonLoop and ghostty interaction easier to
understand
24420e4
Eric Bower  ·  2025-12-19
feat: ctrl+b + d to detach

With support to add more commands
a166953
Eric Bower  ·  2025-12-19
fix: reset terminal modes on detach

Closes: https://github.com/neurosnap/zmx/issues/26
684604d
Eric Bower  ·  2025-12-19
chore: update ghostty-vt
af42d4e
Tristan Partin  ·  2025-12-18
Use XDG_RUNTIME_DIR for the socket directory if defined

XDG_RUNTIME_DIR[0] is a file path for user-specific runtime files, like
sockets.

It will typically be defined on Linux. I can't say for sure on BSDs, and
I know for certain it is not defined on macOS.

Link: https://specifications.freedesktop.org/basedir/latest/ [0]
Signed-off-by: Tristan Partin <tristan@partin.io>
f367693
Eric Bower  ·  2025-12-18
revert: don't force pty resize

This seems to be causing issues with multiple clients connected, instead
we will require clients to force resize themselves for now
d34f8d6
Eric Bower  ·  2025-12-16
chore: publish v0.1.1
ea50fd2
Eric Bower  ·  2025-12-16
docs(changelog): v0.1.1
7b9083b
Eric Bower  ·  2025-12-15
feat(list): sort by session name
b0a88af
Eric Bower  ·  2025-12-15
fix: send SIGWINCH to PTY on re-attach

TIOCSWINSZ alone doesn't notify the shell when terminal size is set.
Now we explicitly signal the foreground process group after setting
the window size, fixing display issues on re-attach.
0fdf98f
Eric Bower  ·  2025-12-12
chore: remove dummy integration tests
651dd7c
Eric Bower  ·  2025-12-11
fix(getTerminalSize): return default size if cols and rows are 0

The issue is that `getTerminalSize` can return 0x0 even when ioctl(TIOCGWINSZ) succeeds. The ghostty terminal library panics when initialized with zero dimensions.

The fix in `getTerminalSize` now validates that both rows and cols are positive before using them, otherwise falling back to the default 24x80.

Closes: https://github.com/neurosnap/zmx/issues/25
a22dba5
Ordo  ·  2025-12-10
add zsh shell prompt doc (#24)

680cedd
Eric Bower  ·  2025-12-10
fix: flake.nix only supports linux atm

`ghostty` does not support packaging nix on mac which I think means we will not be able to support it:

- https://github.com/ghostty-org/ghostty/blob/cf06417b7dfbd0daeb58a9143f9b6ee194cbce26/nix/package.nix#L49
- https://github.com/ghostty-org/ghostty#2824

When our flake tries to build on macOS, it pulls ghostty as a Zig dependency, and ghostty's build.zig calls into apple-sdk/build.zig which needs the Darwin SDK — but ghostty's Nix infrastructure hasn't set that up.
a41aad5
Eric Bower  ·  2025-12-10
feat: homebrew install
5e07a3a
Eric Bower  ·  2025-12-09
docs: changelog spec ref
a1e334e
Eric Bower  ·  2025-12-09
docs: update binaries
163963f
Eric Bower  ·  2025-12-09
chore: v0.1.0
515b12d
Eric Bower  ·  2025-12-09
docs: readme
6918999
Eric Bower  ·  2025-12-09
docs: readme
769b20a
Eric Bower  ·  2025-12-09
docs: added tmux to comparison table
6e2b533
Eric Bower  ·  2025-12-09
fix: remove mac flag
dc63137
Jesse Farebrother  ·  2025-12-05
feat: add version command
a65a2b0
Jesse Farebrother  ·  2025-12-05
chore: build.zig version build option
b5b525c
Eric Bower  ·  2025-12-05
refactor!: postfix uid for socket dir

- first we look for TMPDIR env var or else we default to `/tmp`
- then we look for ZMX_DIR env var or else we create a `/tmp/zmx-{uid}` folder

Since this is a breaking change, you can kill all of your previous
sessions by using `ZMX_DIR=/tmp/zmx zmx kill {sesh}`

Closes: https://github.com/neurosnap/zmx/issues/15

BREAKING CHANGE: this moves sockets to a new location which means none
of your previous sessions will be available
b5e97df
Eric Bower  ·  2025-12-08
docs: comparison table
feb6f3c
Eric Bower  ·  2025-12-06
docs: index site content
4d70b4c
Eric Bower  ·  2025-12-06
feat: docs site
5dc353a
Eric Bower  ·  2025-12-06
fix(attach): cannot attach to session within session

Closes: https://github.com/neurosnap/zmx/issues/20
d3c12e1
Eric Bower  ·  2025-12-05
docs(readme): fish prompt file loc
05042bb
Eric Bower  ·  2025-12-05
chore(release): add shasum files as well
6f106df
Eric Bower  ·  2025-12-05
fix(release): strip mac metadata
6a885bb
Eric Bower  ·  2025-12-05
fix(release): strip apple xattrs
ca2ca8a
Eric Bower  ·  2025-12-05
docs: links for binaries
c15a46b
Britton Robitzsch  ·  2025-12-05
add nix flake (#5)