ForkTTY 0.2.0-alpha.19
Pre-release
Pre-release
[0.2.0-alpha.19] - 2026-07-18
Removed
- Simplified ForkTTY back to a terminal-workspace core by removing the built-in
task Router, provider-neutral Team/Workflow/Feed stores and socket methods,
the right Router rail, Team sidebar section, bottom workflow feed, built-in
MCP stdio server/setup, managed agent-skill installer, provider-selection
settings, and automatic hook updates. Existing unknown config keys are
ignored on load and omitted on the next save. Existing MCP registrations and
installed skills are not changed automatically; follow the
upgrade cleanup to remove
only ForkTTY-managed entries.
Changed
- Reduced the core socket contract from 79 to 50 public/connection-level
methods. Workspace, pane, surface, terminal-text, notifications, metadata,
worktrees, remotes, project actions, events, and thin agent lifecycle
primitives remain available through the owner-only Unix socket and CLI. - Agent hooks are now explicitly opt-in: setup remains available from the
welcome flow and settings, without recurring unread startup reminders or
background hook installation and refresh. - Refined terminal-first onboarding and pane affordances:
Get Startedis the
primary welcome action, duplicate first-run notifications are gone, and the
single-pane split/tab controls have stronger resting contrast. - Made split layouts easier to scan: the focused pane now has a visible accent
hairline, redundant per-pane shell/lifecycle footers are gone, and header and
global status-bar text retain readable contrast at compact sizes. - Consolidated the four identical 500 ms workbench refresh sources into one
callback for layout, sidebar, notification badge, and agent badge updates. - Reframed the workbench around the embedded Ghostty terminal, workspace
sidebar, tabs/splits, navigation, notifications, and status bar; removed
orchestration-only chrome and its periodic refresh work. - Replaced the application icon with a flatter ForkTTY glyph that combines a
terminal prompt, branching path, and cursor line using the restrained dark
workbench palette and a single warm active-path accent. - Major polish for premium, clean, Linear/Cursor/Vercel aesthetic (terminal-first, low noise):
- Workspace sidebar converted from bordered cards with heavy drop shadows to compact inset navigation rows using quiet hairline indicators for active/attention/DnD.
- Reduced full 999px pill radii on badges, status location, welcome button, and keycaps to small precise radii (4-6px). 999px now remains only on intrinsically round controls and true circular dots.
- Keycaps made subtler (lighter background, thinner border, lower weight) to reduce chrome noise.
- Command palette selected state and several tab/workspace DnD feedbacks switched from inset box-shadows to clean hairlines + surface shifts.
- Further quieted the workbench toward Linear/Cursor/Vercel aesthetics:
- Reduced heavy drop shadows on popovers, context menus, command palette search, pane search bars, and notification/agent rows (now subtle 2-4px shadows or border + light inset only).
- Removed outer borders and inset glows from terminal panes; attention no longer paints strong accent borders on the whole pane (signal now via small header dot + subtle header treatment).
- Replaced warm accent-tinted routine hovers/active states (#26211d and similar #1e1a17 warm neutrals) with pure cool grays for calmer interactions.
- Brought pane chrome in line with the quiet workbench finish: the pane
header's agent lifecycle badge becomes quiet colored text instead of a
bordered pill, and the per-pane tab strip drops its stale off-tone background
for the shared pane chrome ground. - Aligned the left workspace sidebar with the same quiet finish: workspace rows
lose their hover/active outlines and read as tinted rounded rows, the
workspace status badge becomes quiet colored text instead of a bordered pill,
and section labels/counts use tracked uppercase and muted weight. - Agent HUD and About ForkTTY now use the quiet hairline + @ft_* palette
treatment: lifecycle and permission badges use small 4px radii and quiet
semantic text colors (no heavy colored 999px pills), About details card is
recessed with @ft_line hairlines and no shadow; pane badges also cleaned. - Systematized the built-in GTK theme around a seven-step type scale, standard
font weights, named surface and semantic color tokens, one success color for
running state, AA-readable muted text, and the documented 4/6/8 radius scale.
Notification kinds and the header title now use quiet text/control shapes
instead of full status pills.
Fixed
- Live terminal working directories containing non-UTF-8 Unix bytes are now
ignored, preserving the last valid cwd instead of poisoning JSON socket
responses. - Claude non-attention notifications now preserve the current agent lifecycle,
so a notification arriving afterStopno longer changes an idle workspace
badge back toWorking. - Persisted
Suspendedagent sessions now remain tombstones: late hooks cannot
revive them, publish side effects, resolve prompts, or advance event order
before an explicit resume. - Claude
SessionStartenrichment now requires complete workspace, surface, and
absolute socket provenance; partial provenance returns the exact continue
response without reading stdin or contacting the socket. forktty hooks doctornow requires a complete managed hook installation:
malformed or partial configs, missing/modified/non-regular Antigravity
wrappers, wrappers or launchers that are not executable by the effective
user, and incomplete Claude, Codex, or OpenCode assets make doctor fail.
Setup repairs exact-content wrappers with stale permissions or symlink type,
and doctor no longer blocks while inspecting a FIFO in a wrapper path.- Restoring a persisted agent terminal with an invalid session ID, resume cwd,
or unsupported provider now reports a red terminal error instead of silently
opening a plain shell in that pane. - Hook-backed permission, elicitation, and attention notifications now carry a
normalized prompt identity and are retained as read history while their
matching desktop notification closes after an accepted provider result. Stale
hook retries cannot clear newer prompts; session cleanup, target remap, and surface or
workspace removal retire only the affected correlations while preserving
unrelated unread attention. Claude Elicitation hooks now create the prompt
notification that ElicitationResult resolves, and PermissionDenied is treated
as a terminal permission result. Result hooks addressed bysurface_idalone
now reuse its inferred workspace target, so they resolve the same prompt as
hooks that provide both target fields. - PTY-persisted panes now resolve their live cwd from the workload behind the
dtach -Amaster instead of mistaking the attached client master for the
shell, so new tabs, splits, restored panes, and Worktree actions inherit the
current directory. - Newly created and restarted embedded Ghostty panes now reliably receive an
initial non-zero layout and inherit the current global terminal zoom. - The GTK launcher now selects the new OpenGL renderer by the name supported by
the loaded GTK version (nglthrough 4.18,glfrom 4.20), avoiding the
renderer-rename warning while keeping the GTK 4.14 AppImage fallback working. - Closing or forgetting an embedded terminal now stops after a bounded wait if
a generation lease is stuck, reports the error, and leaves the surface state
registered for a safe retry instead of hanging removal or shutdown forever. - The packaged GTK/Ghostty smoke now requires the pinned extended line-count
ABI to report beyond a deliberately truncated fragment, so release artifacts
cannot silently fall back to fragment-onlytotal_lines; runtime loading
remains compatible with older libraries that lack the optional extension. - The pinned Ghostty embedding library now exports the optional
ghostty_gtk_surface_read_text_limited_with_total_linesextension, so
packaged bounded reads reporttotal_linesfor the complete selected source
rather than only the returned byte fragment. Older compatible libraries with
only the base limited-read ABI remain byte-bounded and report the returned
fragment's line count. - AppImage
automode now uses an eager loader compatibility probe and selects
host GTK only when both the ForkTTY binary and embedded Ghostty library load;
otherwise it falls back to the bundled GTK/libadwaita stack. Release smoke
coverage masks host GTK in a bubblewrap sandbox and exercises the extracted
AppImage's child helper. - AppImage terminal children now sanitize the selected loader environment only
after the GTK-linkedappimage-child-exechelper has loaded, preserving
TERM=xterm-ghosttyand Ghostty shell integration for Bash, Zsh, fish,
Elvish, and Nushell when the helper executes the real command. ghostty-gtk-lib-probe.sh --ensurenow always invokes the incremental Zig
build before verifying every mandatory embedding ABI symbol.- Ghostty widget close requests now use ForkTTY's Close Pane confirmation;
explicit socket/API close remains noninteractive. - Worktree Create/Attach retries now reuse the same existing modeled workspace
ID and allocate no new modeled surface for the exact
worktree-name/canonical-path identity, while same-named worktrees at different
canonical paths stay distinct. GTK and socket
worktree mutations now share process-local serialization, and removal
retains that transaction even if its requesting future is cancelled while
suppressing automatic terminal respawn and quiescing the exact target. Partial
close or pre-destructive filesystem failures trigger explicit runtime/model
rollback; once verified target deletion starts, removal is conservatively
committed even if filesystem cleanup later fails, avoiding a respawn into a
partially deleted checkout. Failed rollback terminal respawns are recorded as
blocking error status so reconciliation does not retry blindly. - Local terminal panes now track the live shell working directory, use it for new
tabs and splits, expose it through socket context and sidebar chrome, and
autosave distinct per-pane directories for restart instead of reverting to
the workspace launch directory. - Agent integration settings now distinguish an existing provider config from
installed ForkTTY hooks, so a clean system showsNot installedinstead of
the misleadingUpdate available; updates and repairs preserve intentionally
absent providers, the section is labelled optional, and it no longer
describes the removed coordination layer. - Agent hook settings now preserve Claude's installed
--fullprofile, make a
failed-statusRetryrepeat only the check, and tell Codex users to approve
newly written hooks with/hooksinstead of reporting an incomplete setup as
fully configured. - Bounded
context.snapshotto the newest 100 matching notifications and
omitted binary terminal icon data while evaluating prompt risk across the
full matching set, preventing untrusted OSC icon payloads from exceeding the
official client response limit. - Notification socket reads now use bounded cursor pages (
limit1–200 and an
exclusivebefore_id), keep updated items on the newest page, and share one
binary-icon-free projection withcontext.snapshot; the CLI exposes matching
--limitand--before-idflags without auto-fetching additional pages. - Socket responses now have a final 64 MiB encoded-size guard that returns a
same-request-idresponse_too_largeJSON-RPC error instead of sending an
oversized line. Remoteconnectedstate now reflects local terminal-I/O
readiness rather than stale runtime inventory or an independent SSH probe. - Socket clients and startup collision checks now share one deadline-bounded
AF_UNIX connector. A full accept backlog retries with fresh descriptors and
is treated as occupied on timeout, so startup cannot hang or unlink another
listener's socket inode. - Closing the last GTK window now stops new socket dispatch, cooperatively
drains admitted requests, then snapshots scrollback, syncs live directories,
saves the session, applies PTY cleanup, and only then tears down the UI. - Pane and tab menu actions now stay bound to the surface that opened them, so a
later focus or workspace change cannot redirect a split or browser action;
removed targets are quiet no-ops. Pane maximize now counts the real pane tree,
ignores one-pane or multi-tab-only layouts, and clears when a split collapses. - The notification panel now renders rows, count, footer actions, and Open Latest
from one current snapshot, reconciles changes every 500 ms while visible, and
refreshes immediately after Dismiss or Clear without leaving a timer behind. - SSH workspace rows now show
ssh:<host> · connectedor
ssh:<host> · disconnectedfrom the same local terminal-readiness signal used
by remote socket views. - Codex and Claude Code
SubagentStopevents no longer mark the parent session
idle, and Claude CodeTeammateIdlenow publishes the same ready/idle state
persisted for the teammate session. - Workspace rows now keep one consistent height whether or not agent activity
metadata is available, avoiding smaller click targets for quiet workspaces. - Workspace rows now fall back to persisted agent-session lifecycle when a
provider has no current hook status row, so running/needs-input labels stay
consistent across Codex, Claude Code, Pi, OpenCode, Antigravity, and Grok;
real hook status remains authoritative. Codex hook refreshes now also call
out the required/hookstrust review, and doctor no longer implies that a
recorded approval proves the current hook hash is trusted. - Close-pane confirmations now dismiss themselves when another control or
socket client removes the target pane while the dialog is still open. - The grouped
hooksandstatusCLI commands now accepthelp,
--help, and-hwithout trying to contact a running ForkTTY instance. - Repaired the embedded-Ghostty smoke test's scrollback completion check and
post-restart marker assertion so successful runs no longer fail spuriously. - Updated
anyhowto the patched release for RUSTSEC-2026-0190. - Pane tabs now expose native GTK tab accessibility semantics, update their
selected state immediately, and return keyboard focus to the selected
terminal instead of leaving it on the tab control. - Embedded Ghostty tail captures now read the bounded end of full scrollback
when the loaded library supports the limited text ABI; older libraries keep
the safe visible-text fallback. - Switching Settings sections no longer flashes a whitish outline around the
section you are leaving: checked nav items keep a transparent 1px border
instead ofborder: none, so unchecking no longer interpolates the border
color from currentColor (same latent fix applied to spin-button hover). - Settings rows no longer keep a stray whitish outline on the last option you
interacted with: the focus-within row ring is gone (click focus lingers on
toggle/combo rows), entry rows keep a quiet background while typing, and
keyboard navigation still shows the accent focus ring. - Repaired the over-flattened workspace navigation and pane tabs: workspace
rows regain compact inset spacing, rounded selected surfaces, and directional
drag/drop hairlines, while pane tabs stay content-sized, scroll when space is
tight, and keep one restrained warm edge for the active context. - Isolated GTK session-writing tests from the real user state directory, made
environment guards panic-safe, and retried atomic session temp-file name
collisions instead of failing withFile exists. - Propagated piped stdin EOF through
remote-helper pty, so canonical commands
such ascatcan finish instead of hanging after all input is consumed. - Preserved AppImage runtime provenance for renamed launchers in generated hook
commands, used the prerelease-aware zsync update channel, and aligned
release checksum verification with the uploaded.zsyncartifact.
Changed
- Claude's default lifecycle hook profile now keeps
PostToolBatchfor prompt
result correlation, so it installs 26 events;--fulladds only
PreToolUse,PostToolUse, andPostToolUseFailurefor 29 total. - Rejected relative hook config roots during setup/removal so malformed
CODEX_HOME,CLAUDE_CONFIG_DIR,HOME, or related env overrides cannot
make ForkTTY write agent integration config under the current working
directory. - Improved contrast for small sidebar and command-palette labels.
- Fixed AppImage-launched embedded Ghostty panes so new shells receive
FORKTTY_WORKSPACE_ID,FORKTTY_SURFACE_ID, andFORKTTY_SOCKET_PATHafter
the AppImage child-exec helper runs, keeping hooks and agents
targeted at the correct pane/workspace by default.