v0.16.0Neueste
Sessions outlive the window
Sessions that outlive the window
Paneflow 0.16.0 moves every terminal out of the window and into paneflow-host, a detached process with no GPU dependency that owns the PTYs, the child processes and the canonical libghostty terminal state. Quitting Paneflow, closing a window or restarting into an update no longer ends the shells and agents running inside it. The desktop reattaches to the same sessions with their screen and scrollback, and every restored pane resumes at startup without a click. The sidebar lists those sessions as first-class objects with resume, stop, hide and remove, one close policy asks once before a busy agent is stopped, and removing a worktree asks before pulling a checkout out from under a live shell.
Three things change for existing users and are covered under Upgrade notes: session.json moves to schema version 3 and migrates in place, Review mode is removed, and unfocused panes no longer dim by default. The terminal engine (libghostty on every target), the configuration file, the IPC and MCP method names and the paneflow CLI verbs are unchanged; the CLI and MCP bridge gain the ability to work without a window.
The host
paneflow-host ships beside the desktop in the .deb, .rpm, AppImage, .tar.gz, .dmg and MSI. The desktop and paneflow host start share one bootstrap that adopts a compatible host already serving the same PANEFLOW_HOME or spawns one detached from the window: on Windows it breaks away from the desktop's job object with no console and an explicit inherited-handle list, on Linux and macOS it runs under setsid with redirected stdio. The host holds an owner lock so one home has one owner, and a host left over from another Paneflow build is retired and replaced on the next launch; its sessions come back as a new generation with a fresh shell in their recorded directory.
The protocol is JSON-RPC 2.0 lines on a per-home local endpoint. Every connection opens with host.hello, which checks the protocol version, the engine identity and the client build before any effect. Control frames are capped at 64 KiB and checkpoints at 64 MiB, and oversized or malformed input is refused without unbounded buffering. Session records live under <home>/host/; the host keeps the twenty-five most recent finished records and never drops a live one.
Every terminal view attaches to a hosted session: it decodes the native libghostty checkpoint, follows session.output from that offset, skips overlapping bytes and requests a fresh checkpoint on a gap or eviction. Input, resize, paste and focus travel to the host over the control connection, and the mirror never answers terminal queries itself. Reconnecting, ended and unavailable states draw over the last rendered frame with an explicit action. Three integration tests drive a real host and an attached mirror through checkpoint restore without replay, session survival when the client drops, and scrollback retention across the first render resize.
paneflow host start
paneflow host status
paneflow host stop # refused while a session is live, lists them
paneflow host stop --force # stops every live session first, reports the count
paneflow-host session list|create|inspect|stop|restart|remove
The CLI and paneflow-mcp target the host when no window is listening, so listing, read, search, status, fleet and already-authorized send_text keep working against host-owned state. Agent state lives in the host too: it ingests ai-hook events, persists the summary on the session manifest, reconciles busy records as stale after a restart and broadcasts every event on an agent.follow stream the desktop follows. A hidden session shows its host state, or stale while the stream is disconnected.
Sessions in the sidebar
Every session the host owns for a workspace is listed under its last tab. Live rows keep their agent lane; ended rows dim, carry a tooltip with the lifecycle and its age, and collapse under one "N more ended sessions" row past sidebar_ended_sessions (default 5, allowed 0, 3, 5 or 10, Settings > General). Nothing is pruned automatically, a failed listing keeps the previous rows and marks them stale, and a record this build cannot parse is skipped with a log line.
Left-click reopens a live session and resumes an ended one. Right-click offers Open in layout and Stop session for a live row, Resume and Remove from list for an ended one. Hide from Layout drops a pane from the layout while its process keeps running. Resume ended sessions, from the workspace menu and the command registry, brings back every ended restartable pane of a workspace in layout order, and a window that opens with at least two of them offers it once through a toast. A kept session whose directory sits inside an open workspace is listed under that workspace.
One close policy
Closing a pane, a surface tab, a workspace tab, a workspace, or quitting resolves the same policy before anything is removed: stop at once when the session hosts no agent or its agent is finished or errored, ask once for the whole action when an agent is thinking, waiting or in a state the desktop cannot read. The dialog offers Keep running (Enter, the default), Stop and Cancel. Quitting with live sessions asks too, and on_quit (ask, keep, stop) can skip the dialog. Restarting into an update warns how many running sessions it is about to end. Every stop, from a close path or the quit dialog, goes through the host link, which a guard test enforces.
Quitting, restarting and the MSI self-update save the session asynchronously and only exit once the write lands, so closing Paneflow no longer blocks the render thread or drops the final snapshot. When the previous session could not be restored, its file is protected: no new snapshot overwrites it, and a startup prompt offers to retry, quit, or start a new session after backing the original up.
Worktree removal that names what it ends
Remove in Settings > Worktrees used to go straight to git. It now asks the host what is live and, when something uses the worktree, opens a card naming the workspaces rooted there, the tabs bound to it in any window and the sessions whose working directory sits inside it, each identified by workspace, tab position or program and path. Confirming stops those sessions, closes those tabs and workspaces, and then removes the checkout, retrying for a short while on Windows because a process releasing a directory is not instant. Nothing changes when nothing is using it.
Managed worktrees now prove their ownership from the paneflow-owner marker in their own git dir instead of their path under the current worktrees.dir, so changing that setting no longer drops every worktree created under the previous root from the inventory, the keep limit and the removal path. A snapshot restores where it was taken. Repository identity is canonicalized before it is hashed, so two spellings of one path no longer produce two parent directories.
Added
Windows PTYs on a pinned ConPTY runtime
Windows PTYs open through the shared paneflow_host::pty::open entry point, which installs the embedded Microsoft conpty.dll and OpenConsole.exe pair under cache/conpty/<version>/<target> on a worker thread and loads the DLL by absolute path before portable-pty resolves its ConPTY functions. The system renderer, which can emit a DEC 2026 end marker before restoring the cursor, is out of the path. The binaries are pinned in native/conpty/manifest.json, fetched by scripts/fetch-conpty.ps1 and verified twice, and tests/conpty.rs drives a real child through the production PTY. A new PowerShell pane also opens on a prompt instead of the version banner.
Panes in native windows, one tab chrome, a New pane menu
Panes detach into native windows, and tabs and surfaces transfer between windows with one shared tab chrome. The pane tab bar + opens a menu of New pane presets, Terminal then the visible agents then the workspace custom buttons, in the docked bar and in a detached window. Every popup menu shares one geometry (34 px rows, a 1 px gap, 7 px of padding inside the 18 px menu surface), and a unit test fails if those constants stop agreeing.
Settings search and a rebuilt Keyboard Shortcuts page
Settings search matches every setting's title and description as well as the navigation labels, moves the panel to the first matching section without taking focus, highlights the matches in blue and collapses the rows and blocks that do not match, animated over 180 ms. The field is the same 36 px capsule as the sidebar workspace filter, which is now animated too.
The Keyboard Shortcuts page is a register of menu panels: chords drawn as individual keycaps, a 5 px accent dot and a hover reset on every binding that differs from its default, Backspace during recording to unassign an action, a chord another action owns held and flagged until pressed again, group eyebrows naming the context a binding needs (Terminal, Search, Markdown), a Name | Key filter pair, and a footer that counts the customized bindings and holds the global reset.
Manual update check
A manual check from the macOS Paneflow menu, the Windows and Linux Help menu and the command palette, plus a Settings entry on Cmd/Ctrl+,. The result lands in a title bar pill: a spinner while checking, green when up to date, red when the feed is unreachable (both leave after 3 s), and a solid blue pill that installs on click and stays until used. The sidebar update banner is gone, so a single control installs a release.
Tailwind theme, select all, overlay scrollbar
A Tailwind preset, light and dark, with the ANSI palette, foreground, background, cursor and selection from Unpeel (MIT, UX Themes AS, see THIRD_PARTY_NOTICES.md): Tailwind 500 for the normal colors, 400 for the brights, #fafafa on #1a1b1d in dark and #09090b on white in light. It ships its own chrome colors, so the window follows the palette.
Ctrl+Shift+A (Cmd+A on macOS) and Edit > Select All select the whole terminal buffer, scrollback included, the way Ghostty does: leading and trailing blank cells are skipped, the selection stays highlighted, and the text is copied with the usual toast. The buffer is formatted off the render thread.
The terminal scrollbar is an overlay in the style of Ghostty's native scrollers: any viewport move shows it, it holds for a second and fades over 200 ms, hovering the 10 px gutter or dragging pins it, widens the 6 px thumb and reveals a track. reduce_motion snaps instead of fading and terminal.scrollbar: false (Settings > Terminal > Scrollbar) hides it. Refs
#63.
Changed
- Unfocused panes no longer dim by default:
unfocused_pane_opacitydefaults to 1.0. Focus reads from the pane border and title bar; set a value below 1.0 to fade the siblings again. - Programming ligatures are on by default (
terminal.ligatures: true), matching Ghostty. The bundled JetBrains Mono Nerd Font ligates->,=>,!=and//; setfalseto keep the plain glyphs. - On macOS a font size is a point, as it is in Ghostty and every macOS terminal:
font_size: 13renders 13 logical pixels there instead of the 96 DPI conversion that made the same number a third larger than on Linux and Windows. - Every bundled icon moves to a single 24 by 24 outline family at stroke 1.5, workspace folders use the Unpeel folder icons, rows line up on one baseline, and the right panel closes with a layout-sidebar-right icon rather than a cross.
- The attention queue moves from
Cmd/Ctrl+Shift+AtoCmd/Ctrl+Shift+U, freeing the chord every terminal uses for select all. The diff dock maximize shortcut moves toCmd/Ctrl+Alt+M. - The pinned
libghostty-vtarchive moves to Ghostty0c2a290d, which adds theghostty_search_*API the terminal search now uses.
Removed
- Review mode. The Changes and Files tabs of the Agents dock replaced the Review grid, so the mode switch, the diff pane grid, the Workspaces and Changes rails, the diff sidebar and the review keybindings are gone, with the pricing, session usage scans, attribution ranking and worktree diff stats nothing used anymore. The sidebar footer is a single Settings row.
- The profile menu, unreachable since its title bar trigger went, and the theme picker overlay it opened. Theme selection stays in Settings > Appearance; the Files and Help menus move to the title bar.
Fixed
- A pane no longer flashes pure black for about half a second at startup. The placeholder grid shown before the engine's first frame carried an opaque black background instead of the theme background. Measured on a release build with a full-screen capture harness: 21.7 to 23.4 percent of the screen was black from 789 ms to 1301 ms before, 0.0 percent across every frame after.
- Pasting frames the text with
ghostty_terminal_pasteon the runtime thread, so the bracketed paste markers and the newline conversion come from the parser's state at that instant instead of a stale mirror of mode 2004. Mode transitions and each paste frame are traced at debug level underpaneflow::terminal::ghostty. Refs
#65. - Terminal
bright_blackis legible again in Paneflow Dark and Cursor Dark: it sat at APCA Lc 13 against the normalized#181818surface, so the secondary text agents print in that slot was unreadable. The palette value now carries Lc 26. Ctrl+Shift+Fopens the terminal search again on Windows and Linux, where the diff dock maximize shortcut shadowed it, and macOS also getsCmd+F. A test fails the build whenever a global default shares its resolved chord with any other default. Refs
#63.- Terminal search highlights stay on their text while the program keeps writing, and the match count follows the buffer. Plain-text queries run on Ghostty's incremental search, which tracks matches across output, resize, reflow and history pruning; regex queries keep Paneflow's scanner and are re-anchored as the scrollback grows. Refs
#63. - A session listing no longer carries every session's launch environment, which pushed the response past the 64 KiB control frame around fifteen sessions and blinded the sessions sidebar and the worktree removal card. The host no longer refuses a seventeenth attached pane, and a session left running is never forgotten.
- Terminal row layouts are reused across frames and interactive output is prioritized over bulk output; the Ghostty search path and its keyboard navigation shed redundant work.
Upgrade notes
session.jsonmoves to schema version 3. A version 2 file migrates in place on first launch: every workspace gets an id and every terminal surface a session reference, without touching tab order, titles, directories, worktree bindings or detached-window layout. Recorded agent commands stay metadata that restore never re-runs, and the host records under<home>/host/are a new directory older builds never read.- Review mode is removed. Old session files still load: retired keys are ignored and a detached pane saved by Review is dropped instead of the whole session. Review keybindings no longer resolve.
- Two defaults change:
unfocused_pane_opacityfrom0.7to1.0andterminal.ligaturesfromfalsetotrue. Set the previous values explicitly to keep the old rendering. Two keys are added,on_quit(defaultask) andsidebar_ended_sessions(default5), plusterminal.scrollbar(defaulttrue). No key is removed or renamed. - Two default chords move: the attention queue to
Cmd/Ctrl+Shift+Uand the diff dock maximize toCmd/Ctrl+Alt+M. Custom bindings are untouched. - Every package now installs
paneflow-hostbesidepaneflow. The tar.gzinstall.shplaces both; a hand-made install that copies only the desktop binary opens every pane dead, because the desktop resolves the host from its own directory. - The first launch after the update retires any host process left from 0.15.x. Sessions that were running under a 0.16.0 host survive a later update as manifests and restart as fresh shells; their child processes do not survive, and the updater says how many it is about to end.
- On Windows the ConPTY runtime is installed under
<home>/cache/conpty/on first use. The terminal engine stays libghostty on every target, and the IPC and MCP method names and thepaneflowCLI verbs are unchanged.
Install and validation
Every package grows with the host binary and, on Windows, the pinned ConPTY runtime. Download sizes, 0.15.1 to 0.16.0:
| Artifact | 0.15.1 | 0.16.0 |
|---|---|---|
x86_64 .deb |
17.8 MiB | 19.3 MiB |
x86_64 .rpm |
18.0 MiB | 19.7 MiB |
| x86_64 AppImage | 31.3 MiB | 33.9 MiB |
aarch64 .dmg |
29.9 MiB | 32.3 MiB |
| x86_64 MSI | 27.5 MiB | 30.7 MiB |
Download the signed artifacts from this release or use the installation instructions.
Every primary artifact carries a .sha256 sidecar and a minisign .minisig; each AppImage also ships an .AppImage.zsync for delta updates. 35 assets in total.
Pipeline: run 35366739041.
Legs that passed:
- Build:
x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu,aarch64-apple-darwin,x86_64-pc-windows-msvc - Release test gate on Linux x86_64:
cargo fmt --check,cargo clippy --workspace --locked -- -D warnings,cargo test --workspace --locked - Package smoke tests: Debian 12 and Ubuntu 22.04 (
.debpostinst), Fedora 40 and openSUSE Tumbleweed (.rpmpostinst), Arch Linux (tar.gzbinary), Windows MSI install and relay - Auto-update end to end on Linux x86_64
Full Changelog: https://github.com/arthjean/paneflow/compare/v0.15.1...v0.16.0