Overview
ForkTTY is a Linux-native GTK/Ghostty terminal workspace for coding agents and ordinary shell tools.
ForkTTY keeps projects, tabs, split panes, notifications, and git worktrees in one native desktop app. Coding agents run as normal terminal processes: ForkTTY does not route their tasks, own their prompts, manage teams, execute workflow loops, or provide model access.
- Embedded Ghostty-backed terminals with native selection, clipboard, links, and scrollback.
- Quiet GTK chrome with a seven-step type scale, a single warm accent, AA-readable muted text, and consistent 4/6/8px radii. Settings uses General, Integrations, and System navigation with subtle raised preference groups.
- Vertical project sidebar, tabs, split panes, keyboard navigation, drag and drop, and layout restore with each local terminal pane's last live working directory.
- OSC and desktop notifications, unread state, attention rings, and a command palette.
- Git worktree workspaces and an owner-only local socket for focused automation.
Install and first run
Use the AppImage for a portable Linux x86_64 build or the .deb on supported Debian-family systems.
| Path | Use it when |
|---|---|
| AppImage | Portable install on a modern x86_64 Linux desktop |
| .deb | Debian 13/Trixie+, Ubuntu 24.04 LTS+, or a compatible derivative |
| Source | You have the Rust, GTK4, libadwaita, Zig, and Ghostty build dependencies |
$ chmod +x ForkTTY-*.AppImage
$ ./ForkTTY-*.AppImage
$ forktty doctor
AppImage auto mode runs a real eager loader compatibility probe with the effective loader environment. Host GTK/libadwaita is used only when both the ForkTTY binary and embedded Ghostty library load; otherwise AppRun selects its bundled fallback. Terminal child environments are sanitized only after the GTK-linked helper has loaded, immediately before it executes the real command.
Packaging runs ghostty-gtk-lib-probe.sh --ensure --print-path. Every invocation enters the incremental Zig build graph and then verifies every mandatory embedding ABI symbol before the library is accepted.
Embedded Bash, Zsh, fish, Elvish, and Nushell sessions preserve Ghostty shell integration and TERM=xterm-ghostty. A close request from the Ghostty widget uses ForkTTY's confirmation dialog; socket/API close remains noninteractive.
ForkTTY is a DBus single-instance app. A second launch delegates to the running process instead of opening a separate application instance.
When upgrading from a build that included ForkTTY MCP and managed skills, use that older binary's removal dry runs before replacing it. The new binary intentionally does not edit external agent configuration at startup.
# Run with the older ForkTTY binary before upgrading
forktty mcp remove --dry-run
forktty mcp remove gemini --dry-run
forktty skills remove --dry-run
forktty mcp remove
forktty mcp remove gemini
forktty skills remove
The older skill remover preserves removed installs as sibling forktty-agent-orchestration.bak-* directories. Delete a backup only when it is a real directory, not a symlink, and its SKILL.md contains <!-- forktty-managed-agent-skill -->.
Daily use
Use workspaces, tabs, and splits to keep each project and process easy to locate.
- Open the command palette with Ctrl+Shift+P.
- Create tabs and split panes for shells, editors, servers, and coding agents.
- Drag pane headers to rearrange panes and use the compact overlay sidebar to switch projects without resizing terminal panes.
- Use notifications and unread markers instead of polling every pane.
- Enable optional dtach-backed process persistence if terminal processes must survive a UI restart.
Pane chrome is hidden when a workspace contains one pane. Split-pane headers stay compact and reveal actions on interaction, while pane-action hover fills remain inset from the focus hairline; the titlebar is the only permanent global bar. The workspace sidebar overlays the terminal layout instead of reflowing it. Dense flat rows keep selection and reorder cues restrained, pane counts read as borderless metadata, and routine activity summaries stay hidden unless a workspace needs attention or reports an error or terminal-exit state.
Pane and tab actions stay bound to the surface that opened them, even if focus changes before activation. If a new tab cannot start, ForkTTY restores the previous pane layout and focus. Maximize applies only when the real layout has multiple panes, counts tabs as part of one pane, and clears when the layout collapses. While the notification panel is visible it reconciles rows, count, Clear, and Open Latest every 500 ms; Dismiss and Clear refresh immediately. SSH workspace metadata reads ssh:<host> · connected or ssh:<host> · disconnected from local terminal readiness, not a network heartbeat.
Agent integrations
Agents work without setup; optional hooks add lifecycle, attention, and resume metadata.
ForkTTY has no provider selector or built-in task router. Launch the agent CLI you want in a pane. The optional Agent HUD is a thin view over lifecycle metadata, not a team or workflow engine.
$ forktty agents
$ forktty agent-health
$ forktty agent-reclaim-plan
$ forktty hibernate-agent
$ forktty reclaim-agent
$ forktty resume-agent
- Lifecycle state can be delayed; source, age, and evidence fields distinguish persisted metadata from fresh events.
- Non-attention hook notifications are logged without changing lifecycle, so informational notifications after Stop do not revive an idle agent.
- Restored agent panes require valid provider resume metadata; invalid session IDs, resume directories, or unsupported providers show a terminal error instead of opening a plain shell.
- Suspended is a durable tombstone: late hooks cannot revive the session, emit side effects, or advance event order; only explicit resume replaces it.
- Provider credentials and model traffic remain inside each agent CLI.
- External MCP clients and servers remain ordinary terminal processes; ForkTTY does not ship or configure an MCP bridge.
Hooks
Hook installation is optional, manual, dry-run capable, and never refreshed automatically at startup.
$ forktty hooks setup --dry-run
$ forktty hooks setup codex
$ forktty hooks setup claude
$ forktty hooks setup antigravity
$ forktty hooks setup opencode
Settings > Agent hooks names installed providers, confirms setup and updates before writing, and removes only ForkTTY-managed entries. Hooks report lifecycle and attention state; they never move focus or rearrange panes. Setup preserves unrelated user configuration and backs up changed files. Claude installs 25 lifecycle events by default or 28 with --full; Codex installs 10, Antigravity 3, and OpenCode 11.
Hook doctor remains local and read-only. Its version-1 installationCheck regenerates the canonical managed plan and makes overall health fail for malformed, partial, modified, missing, or non-executable assets, including incomplete Antigravity wrapper sets.
Codex can execute hooks through a shared app-server without the terminal pane's FORKTTY_* environment. For local codex-tui sessions, ForkTTY restores lifecycle badges only when one unclaimed same-cwd Codex TUI process belongs to one eligible surface. Another same-cwd TUI, including one outside ForkTTY, makes the fallback stay unassigned.
Claude SessionStart enrichment requires workspace, surface, and absolute socket provenance together; partial provenance performs no socket I/O. Permission, elicitation, and recognized attention hooks carry a provider/session prompt identity. Accepted results retain only the matching in-app notification as read history and close its desktop notification; stale retries are inert, while session cleanup or target removal retires only affected prompts.
Socket CLI and API
The owner-only Unix socket exposes a deliberately small JSON-RPC-like API for terminal workspace primitives.
$ forktty capabilities
$ forktty identify --json
$ forktty context-snapshot --tail-lines 0 --json
$ forktty workspaces
$ forktty surfaces
$ forktty tree
$ forktty read-screen
$ forktty capture-tail
$ forktty notifications
- Workspace and surface methods cover list, create, focus, split, close, text input, bounded visible text, and tail capture.
- Notification and metadata methods publish generic attention, progress, status, logs, and statusline output.
- notification.list returns one oldest-to-newest page: limit defaults to 200 and accepts 1–200, optional before_id is an exclusive retained-item cursor, and the CLI never aggregates pages automatically.
- Context snapshots include the newest 100 selected-workspace and global notifications, omit terminal_metadata.icon_data, and evaluate unread prompt risk across the full matching set.
- Normal response lines are capped at 64 MiB including the terminating newline; an oversized result becomes response_too_large with the original request id.
- Worktree and project-action methods validate repositories and argv-based commands against visible local state.
- Six agent lifecycle methods cover listing, health, reclaim planning, hibernate, reclaim, and resume.
- Router, task strategy, team, workflow, feed, approval orchestration, MCP, and managed-skill methods are not part of the API.
- Existing MCP registrations and managed skills are not removed automatically; the README migration guide documents ownership-marker checks and safe cleanup.
Set FORKTTY_SOCKET_PATH to an absolute path when the default runtime socket is unsuitable. Requests are newline-delimited, size-bounded, and accepted only through an owner-controlled Unix socket.
Official clients and startup collision checks share a deadline-bounded nonblocking AF_UNIX connector. A full Linux accept backlog retries with a fresh descriptor until the deadline; timeout means occupied/foreign, so the existing socket inode is never removed or replaced.
Cooperative GTK shutdown first stops new socket dispatch while the UI remains alive, then drains admitted requests and waits for the socket runtime to drop. Only afterward finalization snapshots bounded terminal scrollback, synchronizes live working directories, saves the session, cleans up configured PTY persistence, and closes the window.
Git worktrees
Represent each editing branch as a visible workspace when parallel processes need separate checkouts.
$ forktty worktree-list --cwd /path/to/repo
$ forktty worktree-create feature/my-task --cwd /path/to/repo
$ forktty worktree-status --cwd /path/to/repo
$ forktty worktree-attach feature/my-task --cwd /path/to/repo
Worktree mutations are limited to repositories already represented by a ForkTTY workspace or surface cwd. Dirty-state checks protect uncommitted work during merge and removal flows.
The Worktree manager keeps the source workspace and path visible while Create, Attach, Merge, and Remove share one mode-specific target form. Its label stays visible, and the removal flow states that the git branch remains intact.
For the exact worktree-name/canonical-path identity, Create and Attach retries reuse the same existing modeled workspace ID and allocate no new modeled surface; same-named worktrees at different canonical paths stay separate. GTK and socket mutations serialize inside the running ForkTTY process, not through a cross-process Git lock. Remove suppresses automatic terminal respawn while the exact target is quiesced, then either commits the model change or attempts to restore the prior runtime/model state before suppression ends. Terminal respawn during rollback can fail; ForkTTY then records a blocking terminal error status before suppression ends.
Configuration and local files
Configuration, sessions, sockets, logs, and optional hook metadata remain local.
| Purpose | Default path |
|---|---|
| Configuration | ~/.config/forktty/config.toml |
| Session layout | ~/.local/state/forktty/session-v2.json |
| Runtime socket | $XDG_RUNTIME_DIR/forktty.sock |
| Logs | $XDG_STATE_HOME/forktty/logs or ~/.local/state/forktty/logs |
[general]
restore_session = true
persist_terminal_processes = false
[terminal]
persistent_scrollback_lines = 0
Privacy and telemetry
Terminal contents, project paths, socket payloads, and agent metadata are not sent to ForkTTY infrastructure.
The default anonymous daily usage ping contains only coarse app and platform information and can be disabled. A separate optional update check queries GitHub releases. Neither includes terminal text, repository content, usernames, hostnames, or install identifiers.
[telemetry]
anonymous_ping = true
endpoint = "https://forktty.dev/api/telemetry/ping"
Security model
ForkTTY assumes same-user local control while defending the socket, filesystem paths, and command boundaries.
- The Unix socket and its parent must be owned by the current user and use restrictive permissions; each accepted connection is additionally verified against same-user (or root) SO_PEERCRED credentials.
- Request lines and terminal reads are bounded; terminal output is untrusted input.
- Project actions use validated argv arrays, never sh -c.
- Worktree operations are restricted to repositories represented by visible ForkTTY state.
- Hook setup preserves unrelated configuration and supports dry-run inspection.
Troubleshooting
Start with doctor, then narrow the problem to packaging, rendering, socket state, or hooks.
$ forktty doctor
$ forktty --json doctor
$ forktty capabilities
- If socket commands cannot connect, launch ForkTTY first or set an absolute FORKTTY_SOCKET_PATH.
- If configuration or session files are corrupt, ForkTTY quarantines the bad file and starts from safe defaults.
- For hook problems, inspect a dry run and the exact provider config file before applying setup again.
- For bug reports, include distro, desktop environment, install method, reproduction steps, and relevant doctor output.
Changelog highlights
The next alpha simplifies ForkTTY around its strongest terminal workspace capabilities.
- Removed the task router, provider selection, team and workflow state, approval orchestration, right rail, bottom feed, and Team sidebar section.
- Removed the built-in MCP bridge, managed MCP registration, managed skill installer, and automatic hook refresh.
- Kept Ghostty rendering, workspaces, tabs, splits, worktrees, notifications, command palette, layout restore, generic socket methods, and optional manual hooks.
Roadmap, limitations, and support
ForkTTY remains alpha, Linux-only, and intentionally focused on terminal workspace depth.
- Known limits include Linux-only support, compositor-dependent quake behavior, optional dtach for process persistence, and source-only browser panes.
- Built-in routing, teams, workflows, feed, approval orchestration, MCP, and managed agent skills are explicit non-goals for the terminal core.
- Use GitHub Issues for bugs, Discussions for questions, and private reporting for security issues.