ForkTTY 0.2.0-alpha.14
Pre-release
Pre-release
Security
- Rejected control characters in restored session identifiers and embedded
Ghostty command-spawn values so tampered session state cannot influence
terminal child argv or environment setup. - Hardened embedded Ghostty GTK library loading by canonicalizing candidate
paths and rejecting relative paths, non-regular files, untrusted ownership,
or group/other-writable files and parent directories beforedlopen, while
allowing packaged AppImage libraries below sticky/tmpmounts. - Limited OSC99 terminal notification icon dimensions before decoding or
forwarding image data to desktop notification servers. - Kitty image snapshots now copy and downsample only the rendered pixel
footprint for each placement and use fallible render-buffer allocation,
preventing malicious terminal output from forcing full-source-image
per-placement copies on every redraw.
Changed
- App dialogs now use tighter shared spacing, shorter copy, and calmer inline
actions across the command palette, shortcuts, worktree, and notification
panels. - The Agent HUD now uses a calmer dense-card layout with compact actions,
subtler status pills, and terminal-like output snippets. - The About dialog now uses a more compact identity layout, calmer metadata
rows, and lighter action buttons. - App chrome now uses quieter top/status bars, subtler split-pane focus,
softer per-pane tabs, and less intrusive pane/browser toolbars. - Sidebar navigation, popovers, badges, and terminal empty/error states now use
calmer density, shorter copy, and less dominant status styling. - Settings now use a clamped, denser layout with calmer inline actions, and the
Agents page presents one recommended integration action plus advanced
per-component actions. - The welcome dialog's agent setup action now opens Settings directly on the
Agents page, so first-time setup shows installed/update state before writing
provider configuration files. - Settings no longer exposes a shell editor; advanced users can still set
general.shellmanually inconfig.toml, while the dialog focuses on
ForkTTY-owned behavior and appearance.
Fixed
- Embedded Ghostty terminals launched from the AppImage no longer leak the
AppImage runtime environment (LD_LIBRARY_PATH,APPDIR/APPIMAGE/OWD,
and GTK/GObject module search paths) into spawned children, so a child
process such as git, an editor, or an agent links against the host's
libraries instead of the AppImage's bundled copies.XDG_DATA_DIRSis left
intact because Ghostty's own shell integration depends on it. - AppImage and Debian packages now include Ghostty's bundled themes, so
embedded Ghostty panes can resolve user configs such as
theme = Catppuccin Mochainstead of falling back to the default colors. - Embedded Ghostty panes now create command-spawned surfaces with a ForkTTY
scrollback cap, preventing long agent transcripts from growing the host GTK
process into multi-GiB memory usage without modifying the user's standalone
Ghostty configuration file. - Embedded Ghostty panes now keep the cursor blink timer disabled while the
rendered terminal state uses a steady cursor, preventing idle OpenGL redraws
from steadily growing RSS for Ghostty configs such as
cursor-style-blink = false. - The embedded Ghostty GTK library probe now builds Ghostty with the stable
ReleaseSafeoptimization profile and a linker-compatible Blueprint helper,
avoiding local Zig/GCC.sframelinker failures andReleaseFast
startup crashes when running ForkTTY from cargo. - Refined the per-pane tab close button styling so hover changes only the X
color instead of drawing a filled control around it. - Embedded Ghostty panes now focus the terminal's internal focusable widget
after new workspace, tab, split, or pane-header selection, so typing reaches
the newly focused pane without an extra click inside the terminal. - Dialogs now handle
Escapein capture phase, so command palette and other
dialogs close even when a search field or text entry has focus. - Embedded Ghostty panes now use a native command-spawn ABI when the bundled
library supports it, so per-surfaceFORKTTY_*environment setup no longer
appears as a typedexec /usr/bin/env ...command in every new workspace.
Older embedding libraries now start Ghostty's default shell without the
ForkTTY environment instead of typing a bootstrap command into the terminal. - Embedded Ghostty socket text reads now use a bounded GTK ABI when the
embedding library supports it, soread_text/capture_tailrequests do not
ask Ghostty to materialize unbounded scrollback in ForkTTY before response
truncation. - Embedded Ghostty scrollback tail capture (
tail_text) now returns an empty
string for a zero-column terminal instead of erroring on an out-of-bounds grid
reference, matching the existing guard invisible_screen_rows. - Failed
agent.hibernateclose attempts now restore the previous unread bit
and status entry instead of leaving the running surface shown as suspended. - Pending embedded Ghostty spawns now lose their orphan-reaper protection
after one reconciliation if their backend surface never appears in the
model, preventing hidden PTY/widget processes from surviving a
spawn/model-removal race. - Bounded the
forktty remote-helper ptystdin relay queue so
non-draining PTY children apply backpressure instead of allowing unbounded
memory growth. - Feed approval rows now use durable notification feed IDs and avoid carrying
approval decisions across newer entries with reused transient notification
IDs. - The socket CLI now writes all success output through the broken-pipe-aware
writer, so piping a command into a consumer that closes early (for example
forktty ping | head -1) terminates cleanly instead of panicking on the
closed pipe. - List socket methods (
team.list,team.inbox,team.events,
workflow.list,workflow.replay) now clamp an explicitlimitto 10000,
matching the existing browser-history cap, so no single request can ask for an
unbounded result set. - Ghostty Nushell shell integration now imports the bundled
ghostty.numodule by absolute path and skips injection when that trusted module is missing, preventing workspace files from shadowing the startup import.
Added
- Settings now includes an Agents page for installing or refreshing ForkTTY
agent hooks and the local MCP bridge after first launch. ForkTTY also
auto-refreshes already-managed hook/MCP entries on startup when a new build
would update them, while leaving first-time setup explicit. - Embedded Ghostty panes now snapshot their scrollback tail into
the session (on child exit, on programmatic close/restart, and via a throttled
poll) when
appearance.persistent_scrollback_lines > 0, matching classic panes, so a
later session save keeps recent embedded output. Restoring that scrollback on
respawn/session restore is wired through an optional
ghostty_gtk_surface_restore_scrollbackembedding ABI (feeds Ghostty's VT
stream, never the child PTY). The pinned Ghostty fork now exports the symbol
(an IO-threadinject_outputmailbox message routed to
Termio.processOutput), so an embedding library built from the current pin
restores embedded scrollback; libraries built before it degrade to a safe
no-op. The Ghostty GTK Probe now builds the embedding.soon Ubuntu and
verifies an embedded pane restart preserves a pre-restart scrollback marker in
capture_tail. Seedocs/ghostty-renderer-embedding-spike.mdfor the
Ghostty-side design. - Bumped the vendored Ghostty pin to
470d3174eb10d25e21d17eff69ffcefdd4f4f91c, which adds the
ghostty_gtk_surface_restore_scrollback,
ghostty_gtk_surface_new_with_working_directory_and_command, and
ghostty_gtk_surface_read_text_limited,
ghostty_gtk_surface_new_with_working_directory_command_and_scrollback_limit
GTK embedding ABIs. - ForkTTY now pins the full upstream Ghostty source as
vendor/ghosttyfor the
cmux-style renderer/widget integration path; release builds package the
vendored Ghostty GTK embedding library for the default pane renderer. - The Ghostty renderer spike is now documented: upstream's current public C
surface embedding API is macOS/iOS-only, so ForkTTY's next renderer step is a
minimal Ghostty-side GTK widget embedding API instead of more parity shims. scripts/ghostty-gtk-build-probe.shnow records the reduced upstream Ghostty
GTK build used before attempting the Linux renderer embedding patch.- A manual
Ghostty GTK ProbeGitHub Actions workflow can run that upstream
Ghostty GTK build on Ubuntu without blocking the normal ForkTTY CI. forktty ghostty-gtk-probecan auto-exit with
FORKTTY_GHOSTTY_GTK_PROBE_EXIT_AFTER_MS, and the manual Ghostty GTK Probe
workflow now smoke-tests the Rust GTK widget bridge under Xvfb after building
the vendored Ghostty GTK embedding library.- The vendored Ghostty GTK embedding library now avoids standalone-app theme
startup when registered inside ForkTTY's host GTK application. - The vendored Ghostty GTK embedding ABI now returns a sunk full widget
reference so the Rust probe can parent the surface without premature dispose. - The vendored Ghostty GTK embedding context now initializes Ghostty's GTK app
state in-place so internal runtime pointers stay valid after context setup. - ForkTTY can pack the vendored Ghostty GTK widget into terminal panes after
ghostty-gtk-embed.sohas been built; this is now the default renderer path,
and terminal spawn records an error instead of falling back to the classic
GTK/Pango/Cairo renderer if the embedded library cannot be loaded or a
surface fails to spawn. - The vendored Ghostty GTK embedding ABI can create surfaces with a working
directory override so embedded Ghostty panes start in the ForkTTY
surface cwd. - The embedded Ghostty GTK pane mode can now forward ForkTTY socket
send_textinput to embedded Ghostty surfaces after the Ghostty core surface
is initialized. - The embedded Ghostty GTK pane mode can now service ForkTTY socket
read_textandcapture_tailrequests by reading visible/full text through
the vendored Ghostty GTK embedding ABI. - Release CI now requires
ghostty-gtk-embed.sobefore packaging, so the deb
and AppImage ship the embedded Ghostty library for the default renderer path. - The embedded Ghostty renderer is now the only terminal pane renderer in the
GTK runtime. The temporary alphaappearance.embedded_ghosttyopt-out key is
accepted on load for compatibility but omitted from new saves and ignored at
runtime.forktty doctorflags a missing embedding library because terminal
panes cannot open without it. - Embedded Ghostty panes now wire surface lifecycle into the
ForkTTY model: title changes mirror into the model, child-process exit drops
the surface from the ready set, sets a closed/Exited (n)status, and raises
an abnormal-exit notification, and a Ghostty close-request tears the pane down
cleanly so no stale pane is left behind. The embedding ABI gains
ghostty_gtk_surface_exit_codeso embedded panes report the real exit status;
older libraries without the symbol fall back to the neutral "Closed". - Embedded Ghostty panes now reach copy/paste/select-all/find
parity with classic panes: theCtrl+Shift+C/V/A/Faccelerators (and the
command palette equivalents) route to the focused embedded surface instead of
no-opping, with find opening Ghostty's native search overlay. The embedding
ABI gainsghostty_gtk_surface_perform_action, which performs a Ghostty
keybinding action by name (e.g.copy_to_clipboard,start_search); older
libraries without the symbol degrade to a logged no-op. Mouse selection
already works natively inside the embedded surface. - Embedded Ghostty panes now route ForkTTY zoom actions to
Ghostty's native font-size actions, soCtrl+plus,Ctrl+minus, reset zoom,
and command-palette zoom affect embedded panes as well as classic panes. - Embedded Ghostty panes now have child-PID ABI plumbing for
listening-port discovery and the socketsurfacesPID field. The embedding
ABI gainsghostty_gtk_surface_child_pid, fed by a newpid_available
surface mailbox message that hands the IO-thread-owned pid to the GTK main
thread race-free; ForkTTY polls the getter briefly after spawn to record the
PID, with a Linux direct-child process fallback while the embedded surface
finishes startup, and the ABI falls back to Ghostty's PTY foreground PID while
the mailbox value is not yet visible. - The socket
surface.listresult, and thereforeforktty surfaces --json,
now includes live runtime fields (shell,cols,rows, andpidwhen
known) in the same rows as the model metadata. - Embedded Ghostty panes now back ForkTTY's Agent HUD tail reads
and inline agent replies, so agent surfaces keep showing recent output and
accepting panel replies when the embedded renderer is enabled. - Embedded Ghostty panes now handle ForkTTY's reset/clear command
by routing it to Ghostty's nativeclear_screenkeybinding action. This
clears the embedded surface through Ghostty; a full terminal-state reset
still depends on Ghostty exposing a dedicated keybinding action. - The Ghostty GTK Probe now requires the embedded
exit_code,child_pid, and
perform_actionABI symbols, and its smoke test verifies socket
capture-tail, embedded pane startup, and that panes expose a positive PID
throughforktty surfaces --json. It also verifies that a clean child exit
marks the pane non-writable with aClosedstatus. - The deb and AppImage packagers now require
ghostty-gtk-embed.soin
vendor/ghostty/zig-out/liband install it intousr/lib, so installed
builds load the embedded Ghostty library via the binary RUNPATH
($ORIGIN/../lib) without needingFORKTTY_GHOSTTY_GTK_LIB. - Team orchestration state is now available as a provider-neutral control
plane throughteam.*socket methods,forktty team-*CLI commands, and MCP
tools, covering leader/worker metadata, task DAGs, mailbox messages,
heartbeats, provider worker launch into tabs, pane dispatch confirmations,
worker health/lifecycle snapshots, idle nudges, safe shutdown requests,
summaries, and event polling without adding parity UI yet.