Repository navigation
v0.6.0 — Sessions & Continuity
Sessions & Continuity: persistent live sessions you can detach from and reattach to, a Flow composer, and a /layout showcase.
Added
- Persistent live sessions: zsh now runs in a small per-user session service (
nmshd, started on demand over a private Unix socket), so closing a window detaches its shell instead of ending it. Running commands keep going.exit, Ctrl+D and/zshstill end the session.NMSH_SESSION_SERVICE=0runs the shell in-process as before. - Reattach: get back to a detached session from the startup prompt, from
/resume(LIVE sessions are listed above ARCHIVED transcripts; Enter attaches, and Ctrl+K kills after confirmation), or withnmsh --attach <id>.nmsh --sessionslists live sessions, andnmsh --newalways starts a fresh one. A session attached in another window is never taken over. - Output while detached: what a detached session prints is kept (1 MB in memory, then up to 64 MB spooled to disk;
NMSH_BACKLOG_MEMORY_BYTES,NMSH_BACKLOG_SPOOL_BYTES). It is added to the transcript on reattach, with a note of commands that completed and anything that exceeded the limit. Fullscreen apps are repainted at the new window size. - Multiplexer interoperability notes: docs/architecture/multiplexer-interop.md records how NMSh behaves inside and around tmux and GNU screen (rendering, resize, job control, fullscreen, paste, and live-session detach when a pane closes), what remains unverified (Zellij), and follow-ups. NMSh stays independent of any multiplexer.
- Live session status:
/resumeLIVE rows andnmsh --sessionsshow what each live session is doing, from evidence only: the running command and elapsed time, the foreground process or a known CLI's name (Claude Code, Codex, Aider, …), active or quiet output, needs attention when the program sent a terminal notification or bell, fullscreen, the title it set, and the last command's result while idle. Nothing is guessed, and paths under your home directory are shown as~/…. /layoutshowcase: preview composer position (Bottom, Top, Flow) × transcript presentation (Normal, Chat) on sample content through the real renderer, then save and apply live. Also under Config → Layout. Nothing in the preview runs or reaches the transcript, journal or/copy.- Flow composer: Config → Composer position → Flow (the command palette's Toggle composer position cycles Bottom, Top and Flow). The prompt and input follow the newest output inside NMSh's document, like a conventional terminal, and scroll with it. Typing while scrolled back returns to them; scrolling alone does not. Menus open below the input, panels pin to the bottom, and Chat presentation and fullscreen passthrough work as before.
- Startup restore is your choice: Config → Sessions → Startup restore (Ask, the default; Always; or Never) and Multiple detached sessions (Ask which, or Open all). With one detached session, NMSh asks: Resume, Not now, Always or Don't resume at startup. With several, a picker restores the ones you select: this window takes one, and the others open in new Ghostty, Terminal.app or kitty windows. Where a host can't open windows, NMSh names the
nmsh --attachcommand for each. Never only skips restoring at launch; it never ends a session. - Live-session hardening: live sessions that end while no window is attached are archived at the next launch or
/resume, with the real exit code or a note that the service stopped or the system restarted. Output captured while detached is kept. A frontend that loses its service reports it and archives the transcript./resumeshows how long each idle live session has been at its prompt. - Exactly-once archiving: launch recovery, Kill Session and live journal checkpoints share a cross-process lock per journal, so concurrent launches never archive a session twice or overwrite a complete archive with partial state.
- Fullscreen reattach: reattaching to a running fullscreen app restores the terminal modes it had turned on, including mouse reporting and bracketed paste.
- Safe updates: each session-service protocol version has its own socket, so live sessions owned by an older service keep running after an update. A newer frontend never touches sessions it cannot verify, and it tells you they exist.
- Session limit: at most 16 live sessions per service (
NMSH_MAX_SESSIONS). When the limit is reached, a new window falls back to an in-process shell with a notice. Detached sessions are never ended to make room.
Fixed
- Interactive terminal UIs that draw inline (agent CLIs such as Claude Code, including under a wrapper or alias like
claude-account2) now get the terminal. NMSh hands over as soon as a running program turns on terminal input modes (bracketed paste, mouse, focus events or the kitty keyboard protocol), not only when it switches to the alternate screen or has a known name. Keys reach the program, NMSh's composer steps aside, no control sequences leak into the transcript, and the same applies after reattaching. Ordinary commands, including progress output, stay in NMSh. - Restoring several detached sessions (the startup picker or Open all) opens every selected session again. NMSh used to exit while waiting for the first extra window to open, printing "Detected unsettled top-level await": only that window appeared, and the current window never attached. In Terminal.app this looked like
nmshfailing to start. A window launcher that hangs now times out after 15 s, and that session'snmsh --attachcommand is named instead. - Ctrl+Z suspends the foreground job again (raw
^Zand the Kitty keyboard encoding), andjobsandfgwork as in plain zsh. - After Ctrl+Z,
jobscould list a straysuspended (tty output)job. NMSh's own prompt hook ransttyas a job, and it could be stopped when it ran before zsh had taken the terminal back. The hooks now change terminal modes outside job control. - The session service no longer crashes when a window resize races a shell's exit. node-pty could throw
EBADFfor a PTY that had just closed, which inside nmshd would have ended every live session. Other resize failures are now reported to that window instead of ending the service. - A launch notice (for example, sessions archived while no window was attached) is no longer erased when the window reattaches to a live session.
Removed
scripts/pty-history-smoke.mjs: its checks had gone stale (it asserted retired UI text), it ran against the real config and live session service, and deterministic tests now cover everything it checked.