Skip to content

Lucenx9/forktty

Repository files navigation

ForkTTY

ForkTTY

Linux-only multi-agent terminal with split panes, git worktree workspaces, session restore, and prompt-aware notifications.

Run several coding agents in one desktop window. ForkTTY keeps their terminals and workspace state separated, can place agents in isolated git worktrees, and surfaces unread prompts when a background workspace needs attention.

License: AGPL-3.0 Build Release Rust Tauri

Download Latest Release

ForkTTY UI preview

Status: Early development (v0.1.2). ForkTTY is usable on Linux, but the runtime surface is still changing. There are no macOS or Windows builds.

Features

  • Linux desktop app built with Tauri v2, Rust, React 19, TypeScript, and Vite.
  • xterm.js terminals using @xterm/xterm 5.5 with Fit, Search, and Canvas addons.
  • Split panes powered by react-resizable-panels, with horizontal/vertical splits, drag resize, and Alt+Arrow navigation.
  • Workspace sidebar with branch, directory, worktree status, unread counts, notification previews, drag reorder, and optional collapsed/right-side layouts.
  • Git worktree workspaces using native git2 operations, configurable nested/sibling/outer-nested layouts, and optional .forktty/setup / .forktty/teardown hooks.
  • Session persistence for workspace order, active workspace, pane tree, focused pane, names, working directories, branches, and worktree metadata. PTYs and scrollback are not persisted.
  • Session restore hardening: malformed or unsupported session files are ignored and quarantined; pane trees are validated before restore.
  • Prompt-aware notifications from OSC 133, Claude-style prompt patterns, and OSC 9/99/777 terminal notification sequences.
  • Noise controls for notifications: switch/restore suppression, short-window dedupe, and no repeated prompt notifications while a workspace is already unread.
  • Welcome/onboarding and polished dialogs: first-run welcome overlay, safer focus defaults for destructive modals, and improved empty/loading/error states in settings, branch picker, command palette, notification panel, and pane spawn failures.
  • Ghostty theme compatibility for local colors, font family, font size, and palettes, with explicit ForkTTY config taking precedence.
  • Local socket API over a user-private Unix domain socket for workspace, surface, notification, worktree, and metadata automation.
  • System tray integration with unread-count tooltip and click-to-focus behavior when the desktop environment supports it.
  • Privacy-first defaults: no telemetry, no update checks, no external network calls. See PRIVACY.md.

Quick Start

Requirements

Debian / Ubuntu:

sudo apt install libwebkit2gtk-4.1-dev build-essential \
  libssl-dev libayatana-appindicator3-dev librsvg2-dev

Fedora:

sudo dnf install webkit2gtk4.1-devel gtk3-devel libappindicator-gtk3-devel librsvg2-devel

Build and Run

git clone https://github.com/Lucenx9/forktty.git
cd forktty
npm install
npm run tauri:dev

Build Installers Locally

npm run tauri:build
sudo dpkg -i src-tauri/target/release/bundle/deb/ForkTTY_*.deb

The AppImage is emitted under src-tauri/target/release/bundle/appimage/ when the AppImage bundle is produced:

chmod +x src-tauri/target/release/bundle/appimage/ForkTTY_*.AppImage
src-tauri/target/release/bundle/appimage/ForkTTY_*.AppImage

The packaging script normalizes AppImage root symlinks, rejects unsafe icon values containing / or .., and patches the AppImage runtime environment for common WebKitGTK/GPU issues.

Install from GitHub Releases

  • Release page: https://github.com/Lucenx9/forktty/releases/latest
  • Debian / Ubuntu / Linux Mint: download ForkTTY_*.deb, then install with sudo dpkg -i.
  • Other Linux distributions: download ForkTTY_*.AppImage, chmod +x it, then run it directly.
  • Prefer the native .deb on Debian-family systems; use the AppImage as the portable fallback.
# .deb example for the current 0.1.2 release
curl -LO https://github.com/Lucenx9/forktty/releases/latest/download/ForkTTY_0.1.2_amd64.deb
sudo dpkg -i ForkTTY_0.1.2_amd64.deb
# AppImage example for the current 0.1.2 release
curl -LO https://github.com/Lucenx9/forktty/releases/latest/download/ForkTTY_0.1.2_amd64.AppImage
chmod +x ForkTTY_0.1.2_amd64.AppImage
./ForkTTY_0.1.2_amd64.AppImage

Keyboard Shortcuts

Action Shortcut
New workspace Ctrl+N
New worktree workspace / branch picker Ctrl+Shift+N
Close workspace Ctrl+Shift+W
Jump to workspace 1-9 Ctrl+1..Ctrl+9
Split right Ctrl+D
Split down Ctrl+Shift+D
Navigate panes Alt+Arrow
Close pane Ctrl+W
Find in terminal Ctrl+F
Copy selection Ctrl+Shift+C
Command palette Ctrl+Shift+P
Notification panel Ctrl+Shift+I
Jump to unread workspace Ctrl+Shift+U
Settings Ctrl+,
Zoom in / out / reset Ctrl+= / Ctrl+- / Ctrl+0

These shortcuts intentionally override some terminal defaults while the main app surface is focused. Text inputs, modals, the branch picker, and command palette block workspace-mutating shortcuts.

Configuration

Config file: ~/.config/forktty/config.toml. All fields are optional.

[general]
# "auto" reads Ghostty colors/fonts when available; "builtin" uses the fallback theme.
theme_source = "auto"

# Must be an absolute path to an executable file. Default: $SHELL, then /bin/bash.
shell = "/bin/bash"

# Worktree placement: "nested" (.worktrees/), "sibling", or "outer-nested".
worktree_layout = "nested"

# Empty disables custom commands.
# If set, the first token must be an absolute path to an executable file.
# Additional static arguments are currently supported through shell_words parsing.
notification_command = ""

[appearance]
font_family = ""
font_size = 14
sidebar_position = "left" # "left" or "right"

[notifications]
desktop = true
sound = true

Config loading is bounded to regular files of at most 1 MiB for ForkTTY's TOML config. Invalid saved settings are rejected when written from the app. Loaded config values are normalized where possible; spawned shells still require a valid executable path.

Ghostty users: ForkTTY reads ~/.config/ghostty/config and theme files under ~/.config/ghostty/themes/ for compatible colors, font family, font size, and palette entries. Explicit [appearance] values override Ghostty-derived values.

Custom Notification Command

notification_command runs in addition to desktop notifications when ForkTTY dispatches a notification.

  • The command is split with shell_words; ForkTTY does not use sh -c.
  • The first token must be an absolute path to an executable regular file.
  • Additional static arguments are passed as argv if present.
  • Pipes, redirection, variable expansion, globs, and shell operators are not interpreted.
  • The notification payload is passed through environment variables:
    • FORKTTY_NOTIFICATION_TITLE
    • FORKTTY_NOTIFICATION_BODY

Example:

[general]
notification_command = "/usr/bin/notify-send --app-name ForkTTY"

A stricter future policy that disallows extra notification_command arguments is tracked as a follow-up, not current behavior.

Session Restore

ForkTTY saves workspace layout through a debounced store subscription and attempts a final best-effort save on window unload. On startup it restores the workspace list, active workspace, pane tree, focused pane index, working directories, branch labels, and worktree metadata.

Restore does not preserve PTY processes or scrollback. New PTYs are spawned for restored panes. Corrupt or structurally invalid session files are renamed to session.json.bad-* and ignored so the app can start with a clean workspace.

Prompt notifications are suppressed briefly during restore and workspace switches to avoid false positives from shell redraws and terminal resizing.

Worktree Behavior

Worktree workspaces are optional. Ctrl+Shift+N opens the branch picker, which can create a new branch from HEAD or attach a worktree to an existing branch. Layout is controlled by general.worktree_layout.

Socket-driven worktree.* operations validate caller-provided cwd values against repositories already open in the frontend. Subdirectories and linked worktrees in the same open repository are accepted; unrelated repositories are rejected. Removing the last worktree-backed workspace creates a replacement plain workspace rooted at the repository fallback path before closing the worktree workspace.

Architecture

Frontend (React 19 + TypeScript + Vite)
  - @xterm/xterm 5.5 with Fit, Search, and Canvas addons
  - react-resizable-panels recursive pane layout
  - Zustand workspace/config/metadata stores

Tauri v2 IPC
  - invoke commands for control paths
  - Channels for PTY output streaming
  - local event bridge for socket API requests

Backend (Rust)
  - portable-pty for PTY lifecycle
  - git2 for repository and worktree operations
  - output_scanner for OSC/prompt detection
  - notify-rust for desktop notifications
  - tokio + serde_json for the Unix socket API

Security Summary

  • Linux-only local desktop threat model; the current user is the primary trust boundary.
  • Unix socket defaults to $XDG_RUNTIME_DIR/forktty.sock, validates private parent permissions, uses owner-only socket permissions, and enforces a 1 MiB request limit.
  • Shell path and notification_command program path must be absolute executable files.
  • Custom notification commands use argv execution, not sh -c; title/body are delivered via environment variables.
  • Worktree names and paths are validated; hook execution is restricted to .forktty/setup and .forktty/teardown inside verified worktrees.
  • AppImage packaging rejects unsafe icon path traversal values and refuses absolute root symlinks.
  • CSP restricts the WebView to local app content.

See SECURITY.md for reporting instructions, residual risks, and the full local trust model.

Known Limitations

  • Linux only. There are no supported macOS or Windows builds.
  • Dark theme only. CSS has limited system-preference handling, but no light-mode toggle.
  • PTYs and scrollback are not persisted across restart.
  • Session saves are debounced and the final beforeunload save is best effort.
  • No idle-time notification detector; only prompt/OSC notification triggers are active.
  • No end-to-end PTY backpressure. The frontend bounds pending output and may drop buffered bytes under sustained overload.
  • Full Tauri GUI smoke tests and routine manual runtime QA are still backlog items.
  • Documentation screenshots may lag small UI polish changes.

Contributing

ForkTTY is in active early development. Keep changes small, verify the relevant surface, and avoid documenting behavior that is not implemented in the current code.

Useful commands:

npm run tauri:dev                         # Dev mode
npm run build                             # TypeScript + Vite production build
npm run lint                              # ESLint for src/
npm run test                              # Vitest suite
npm run tauri:build                       # Production Tauri build via packaging script
npm run tauri:info                        # Tauri environment info
cargo fmt --manifest-path src-tauri/Cargo.toml --check
cargo clippy --manifest-path src-tauri/Cargo.toml -- -D warnings
cargo test --manifest-path src-tauri/Cargo.toml
npx prettier --check src/

See SPEC.md for technical details and ROADMAP.md for implemented, planned, and known backlog work.

Inspiration

Built from scratch for Linux, inspired by cmux (macOS-only, Swift/AppKit).

License

GNU Affero General Public License v3.0 (AGPL-3.0-only)

About

Linux-first multi-agent terminal with split panes, isolated git worktrees, and smart notifications for AI coding workflows.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors