Skip to content

v0.6.0 — Sessions & Continuity

Choose a tag to compare

@raiseCatError raiseCatError released this 29 Sep 16:27
· 351 commits to master since this release
04496ec

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 /zsh still end the session. NMSH_SESSION_SERVICE=0 runs 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 with nmsh --attach <id>. nmsh --sessions lists live sessions, and nmsh --new always 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: /resume LIVE rows and nmsh --sessions show 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 ~/….
  • /layout showcase: 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 --attach command 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. /resume shows 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 nmsh failing to start. A window launcher that hangs now times out after 15 s, and that session's nmsh --attach command is named instead.
  • Ctrl+Z suspends the foreground job again (raw ^Z and the Kitty keyboard encoding), and jobs and fg work as in plain zsh.
  • After Ctrl+Z, jobs could list a stray suspended (tty output) job. NMSh's own prompt hook ran stty as 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 EBADF for 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.