Skip to content
Conduit

mcp server

chda

A terminal that runs one coding agent per git worktree and shows which one needs you: Claude Code, Codex, Gemini CLI, Copilot CLI, OpenCode. Ghostty core, Rust, GPUI.

magicsih/chdacommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 25, 2026

Why a worktree terminal

Versions 1.4.0, 1.5.0 and 1.5.1 were withdrawn after session-service failures. Current development uses app-owned terminals with no independent session service. Download the current release.

If you are using 1.4.0, 1.5.0 or 1.5.1, download the signed ZIP from the current release, quit the GUI and replace chda.app. Their built-in updater requires the withdrawn service and cannot install service-free releases, including 1.5.2. Finish service-owned runs first. Keep the existing profile files; the replacement starts its own terminals and cannot reattach to those runs.

One worktree, one task, one agent. Coding agents such as Claude Code and Codex are most productive when each runs in its own git worktree, but a normal terminal leaves you mapping tabs to worktrees in your head. chda puts that map in a sidebar: which worktree is running which agent, which one is waiting for your answer, which one is finished and unread. Creating a worktree, launching the agent, merging the branch and cleaning up all happen from the same panel, without leaving the terminal.

The terminal core is libghostty-vt, so escape sequences, Unicode and key encoding behave like Ghostty. The app is Rust on GPUI.

Install

macOS

brew tap magicsih/tap
brew trust magicsih/tap
brew install --cask chda

Or download chda-<version>-macos-universal.zip from the releases page. The app is signed and notarized.

Requirements: macOS 14 or newer (Apple silicon or Intel), git on PATH. gh is optional and adds pull request badges. On a managed Mac where Homebrew cannot write to /Applications, add --appdir=~/Applications.

Linux

Download the x86_64 AppImage or portable archive from the Linux downloads page. See Linux installation for checksum verification, graphics requirements, X11 and Wayland support, shortcuts and saved data.

A quick tour

Captured in chda 1.0.25 with a local demonstration repository and sample agent events. The recording contains no private projects or conversations.

  1. Press cmd-shift-o (or click "+ repo") and pick a git repository. It appears in the sidebar with its worktrees. A folder that is not a repository can be initialized with git init on the spot or added as a plain folder: one row for terminals and agents, without git badges or worktrees.

  2. Click "+" next to the repository, type a branch name (or leave it empty for a random one like brisk-otter), and optionally a note saying what the task is, then press Enter. chda creates <repo>.worktrees/<branch> and opens a tab there; the note becomes the row's label. To stack work on another branch, right-click its worktree and choose "New worktree from this branch..."

  3. Right-click the worktree and choose "Run Claude Code", "Run Codex", "Run Gemini CLI" or "Run MiniMax Code". The agent starts in that worktree with chda's hooks attached. If your config already has an explicit agents list, add "gemini" and "minimax" there. Copilot CLI and OpenCode join through that same list, and your usual flags through [[agent-presets]]. You can also type codex directly in a chda zsh, bash or fish terminal with shell integration enabled; its status is tracked too.

  4. Watch the dot next to the branch:

    DotMeaning
    greyno live agent
    yellowlive agent, idle and ready
    blueworking
    orangewaiting for your input (you also get a notification)
    greenfinished; clears when you look at the tab
  5. When the branch is done, click its +12 −3 badge to read the diff in a tab, then right-click it and choose "Merge into main and clean up". chda merges, removes the worktree and deletes the branch, and refuses when there are uncommitted changes, unpushed commits or an open pull request.

Your tools, in the worktree

Run your own commands from a worktree's menu, the command palette or a shortcut. Open them in a tab, a split or a floating terminal; the process runs in that worktree through your login shell. Move a running pane to another tab or window without losing its process or scrollback.

Diagrams and Markdown, rendered offline

Agents answer with Mermaid diagrams and write design docs in Markdown. chda finds Mermaid in a pane's output ("View diagram" on the block, or "View last diagram" in the palette) and previews Markdown files (right-click a .md path, or "Preview Markdown" in the palette). Both open as local pages in your browser: nothing is uploaded, remote content is blocked and scripts in the document do not run. Mermaid blocks inside Markdown become diagrams too.

Read project documents with Leaflit

Work in chda. Read in Leaflit, a separate macOS Markdown reader for plans, specs and notes from coding agents. After installing Leaflit, run this from a shell in the chosen worktree:

leaflit ./plan.md

Keep the document beside your terminal while the agent works. Leaflit follows saved changes and offers Find, Outline, Mermaid diagrams and LaTeX math. For a small correction to generated Markdown, switch to Source and save explicitly.

chda's built-in browser preview remains available for quick checks. Leaflit is an optional companion for Apple Silicon Macs running macOS 14 or later; chda's Intel Mac and Linux support does not extend to Leaflit. See Leaflit's workflow and installation or its source repository.

Features

AreaWhat you get
TerminalGhostty-accurate VT handling, hard line breaks preserved through reflow and safe resizing while viewing scrollback, true color, minimum text contrast of 3 by default (Ghostty minimum-contrast from 1 to 21; 1 disables adjustment), readable text even when a running agent retains its prompt background across a theme change, wide glyphs, IME input, mouse selection and reporting, scrollback search (cmd-f), cmd-click links and file paths, including unquoted explicit paths with spaces or parentheses, quoted paths, and paths after a note such as (see …), across soft-wrapped rows. The longest existing path wins over a shorter existing prefix; hard newlines and adjacent explicit paths stay separate. Overlong candidate searches leave the path unresolved. Hover, click and path menus share the target, and a deleted target is not replaced when activated, right-click actions on paths (reveal in Finder, open a tab or cd there, copy), drag and drop paths, inline images (Kitty graphics protocol), Mermaid diagrams in agent output rendered offline ("View diagram"), Markdown files previewed in the browser (right-click a .md path, or "Preview Markdown" in the palette), font size shortcuts, prompt jumping (cmd-up / cmd-down) Right-click a terminal selection for Copy for sharing: review and edit a plain-text preview before copying. It uses only uniquely matched assistant text from the selected pane’s exact conversation; partial selections stay partial and ambiguous selections remain unchanged. Confirmed Claude Code 2.1.296 and Codex 0.162.1 layouts restore indentation in uniquely matched code and text subsections, including Claude nested hyphen lists, while retaining confirmed older gutter layouts. Hidden code-fence delimiters and the rest of an answer are never added. Duplicate matches, incomplete transcripts and transformed tables, quotes or bullets that cannot correspond exactly keep the original selection. Ordinary Copy keeps the existing terminal selection behavior. Changed conversations block copying; cancelling restores typing focus. Linux also resolves the foreground directory through /proc when shell directory reports are unavailable. On Linux, Ctrl+Shift+C/V copy and paste, Ctrl+Shift+F opens search, and Ctrl+click follows paths and links. Ordinary Ctrl+C and other shell controls still reach the foreground process. Bundled Nerd Font icons render without installing a system icon font. Bash prompt titles preserve directory names containing spaces and Unicode without shell errors. When a program exits without turning mouse reporting off, the next zsh, bash or fish prompt takes the mouse back, so moving the pointer no longer types report fragments such as 35;105;44M into the command line; a program started later can request mouse reports again.
Tabs and splitsCmd+1 through Cmd+9 and Cmd+0 select the first ten Sessions rows in their displayed order across repositories, split agent panes, Git views and terminal tabs, including when Sessions is collapsed or the sidebar is hidden. A missing position does nothing. Cmd+Alt+0 resets the font size. After the last window closes, clicking the Dock icon or opening chda from Finder opens one new usable window. An existing window comes forward without duplication, including when minimized. Open another window with cmd-shift-n. Windows, terminal, Git tree and Diff review tabs, splits, active focus, directories and exact supported agent conversations come back after restart. A window that was in native full screen reopens at its last windowed size. Drag a tab onto another to reorder the tab bar; the order is saved and restored. Right-click a tab or a Sessions row, or use the palette, to move a running pane to a new tab, beside the pane of another tab, or to another or a new window: its process, scrollback, agent status, child activity and conversation stay with it, and a tab left empty closes without asking. Agent conversations resume in the latest directory confirmed for that exact conversation, then the captured launch or transcript directory; a missing confirmed directory keeps an error pane without resuming elsewhere. Previous working activity remains available separately from new runtime output. Only actual terminal output and delivered input update activity; theme, resize, selection, search and scroll changes keep quiet panes quiet. Every tab has a visible close button, including long labels and inactive tabs; cmd-w closes the focused pane. Working or waiting agents, and idle parents with working, waiting or unknown children, ask before stopping. Cancel is the default; Tab selects the other button and Enter or Space activates it. When a shell exits (exit or ctrl-d), its pane closes like cmd-w, whatever its exit code. A program chda started, such as a managed agent or a [[commands]] tab, closes the same way when it succeeds; a failure keeps its pane with the exit status, read-only output and Start shell. Closing the shown tab, with exit, its close button or cmd-w, shows another tab of the same branch, or else no tab: the window stays on that branch, the sidebar keeps it selected, and + at the end of the tab bar or cmd-t opens a new terminal there. A window stays open when its last tab closes; cmd-w on a window without tabs closes it. Linux uses Ctrl+Shift+T/W for tabs, Ctrl+Shift+D/E for splits and Alt+1 through Alt+9 and Alt+0 to select the first ten Sessions rows. Ctrl+0 resets the font size.
App updatesIn a configured, signed macOS release, click Update to download, verify and install with Sparkle. Progress is shared across windows; installation waits for current repository tasks and unfinished input before preserving sessions. macOS asks for administrator approval when required. Windows briefly reopen while running shells and agents, terminal text and scrollback, pane IDs, layouts and focus reconnect. Failed installation or startup reopens the retained signed app with the same sessions. Terminals that have used inline images block the update without stopping their processes. Release notes and version dismissal remain separate; automatic downloads and installs are off. v0.1.19 requires one manual update first. Linux offers the latest stable Linux package as a manual download. It does not offer a macOS-only release or stop running shells while opening the download page. Versions 1.4.0, 1.5.0 and 1.5.1 require a manual signed-app replacement because their updater requires the withdrawn session service. Finish service-owned runs first; the replacement opens app-owned terminals and cannot attach to those runs.
Title barThe focused pane's repository and branch-note alias appear as repo - task; the branch is the fallback. Custom tab names remain on tabs without hiding the repository context. Hover for the repository, full note, branch and worktree path. Open the focused worktree in a chosen installed editor or Finder. Linux discovers installed folder-capable desktop applications and available icons, and opens the selected folder through gio; the default file manager uses xdg-open. Linux has a Commands button and draws minimize, maximize and close controls plus resize edges when the compositor does not provide window decorations. Linux client window controls preserve the visible window size when minimizing and restoring.
NotificationsThe title-bar notification control stays immediately before the installed-app picker, even with the sidebar hidden or no available picker. Window-local history lists severity, date and UTC time, message and known directory/tab/pane context newest first. Opening reads only existing arrivals; later arrivals remain unread. Selecting an agent event goes to its exact still-open pane. Operational errors and successes no longer overwrite a single sidebar message; an ongoing branch update changes one entry. OS notifications and provider usage controls remain available. Programs can ask for a notification with OSC 9 or OSC 777, as Ghostty, iTerm2 and kitty support: the request adds an entry with its pane, marks the tab and, when the pane is out of view, sends an OS notification that focuses that pane. Text is shown plain and truncated, each pane is limited to one a second, panes with a live agent rely on its own notifications, and the notifications setting turns these off too. History retains at most 500 entries and reports removed older entries. Normal restart clears it; session-preserving updates retain each window's history and read state. On Linux, desktop notifications use the session D-Bus service; clicking one returns to its exact pane. Delivery runs off the UI thread, and a missing notification service does not block terminal input. Linux does not show a launcher badge or play a separate terminal alert sound.
SidebarRepositories and plain folders, worktrees, dirty / ahead / behind / conflict badges, lines added and removed against the default branch (click for a read-only diff tab), pull request state via gh, glab or tea, and open-tab counts. Two peer sections, Sessions and Projects, each have a header outside their own scrolling list; the wheel or trackpad moves only the list under the pointer. Sessions has one row per agent pane, so agents in split panes each get a row, with nonshrinking #1, #2 numbers when they share a tab; labels and provider names give way before the number; one row per Git tree or diff review tab; and ordinary terminal tabs last, all in tab and pane order. Rows never move when an agent starts working, waits, finishes or goes idle, and a live idle agent is listed once. Each row shows its repository and branch, or the branch note with the Alias / Branch toggle, what it is, time since the last terminal activity after a minute of inactivity and a status icon whose tooltip names the state: Working, Waiting for input, Turn complete, Idle, No live agent, Terminal, Git tree or Diff review. Every ordinary terminal tab and agent pane keeps a close control; clicking it checks the latest parent and child activity before applying close confirmation. Sessions grows with its rows up to 40% of the sidebar and then scrolls, takes the remaining height when Projects is collapsed and shows No open sessions when empty. Clicking a session, switching tabs or panes and jumping to an agent focus the exact pane and highlight its branch in Projects, which scrolls only enough to reveal a clipped worktree while keeping its repository name visible. That repository name stays pinned at the top of Projects while you scroll and works like the repository's header: click it to collapse the repository, right-click it for the repository's menu. Sessions never scrolls by itself, and a collapsed Projects section stays collapsed with the highlight updated. Navigation opens the target project section and repository while keeping the top-level Projects container collapsed if the user closed it. Projects keeps the main worktree first, then branches by name, with path as a tie-breaker and detached worktrees last. Background output, status changes, transcript indexing and refreshes move neither list nor a deliberately selected branch. Both sections collapse independently, show their counts while collapsed and remember the choice across restarts; earlier ACTIVE and IDLE settings carry over as a collapsed Sessions only when both were collapsed. Every badge and header button explains itself on hover, and "+ repo" names its shortcut, cmd-shift-o. Repositories and folders, including Starred branches, sit beneath Projects. Each repository header collapses its own worktrees, and one button beside "+ repo" collapses every repository while any is open and expands them all otherwise (also View > Expand All Repositories / Collapse All Repositories and the palette); the Projects section toggle stays separate, and each repository's state is remembered across restarts. Drag a repository header above or below another to reorder the list; a line marks where it lands, Projects scrolls near its edges, and the order is saved without moving folders or changing Git. Right-click a branch and choose "Add to Starred" to keep it in a Starred list within Projects, per repository and saved across restarts. Click a branch in Projects or Starred to open it, reusing its most recently focused pane across windows or the configured default action; a double or triple click opens it only once. Right-click either list for Open terminal or explicit agent actions. A missing Starred worktree stays selectable and never creates a terminal or worktree. Click its star to unstar it without leaving the current tab. If the system cannot open the folder picker for Add repository, chda keeps running with terminals, typed input and settings unchanged, records one error in the title-bar notifications, and you can try again or drop the folder on the sidebar. A folder you add from the picker, the palette or a drop on the sidebar becomes the selected row at once: Projects and the folder's group open if collapsed and scroll just far enough to show it, the terminal you are working in keeps its focus, a later refresh keeps the selection, and when several folders are added together the last one is selected. Cancelling, a picker that cannot open, or declining a plain folder leaves the selection and scroll position as they were. Claude Code and Codex sessions in the Sessions list get a small pixel identicon before their name, made on your machine from the provider and the full session id, so sessions with the same name stay apart and each keeps its picture through status changes and resumes; rows stay as tall as before, and a sidebar narrower than 200px leaves the pictures out so names keep their room. Click it, or run Show session icon from the palette, for a 160px view with the provider and full id; Escape, Close or a click outside closes it, and the click never activates the session. A working agent shows a three-dot brightness wave, an agent waiting for input an orange "!" badge on a tinted row, a finished turn a green dot, a live idle agent a yellow dot and a row with no live agent a gray dot. On light themes, or wherever a color would fade into the sidebar or tab bar, it deepens or lightens within its hue so every status icon keeps at least 3:1 contrast, selected rows included. Stars and Git badges retain their hues and at least 3:1 contrast on normal, selected and waiting rows in light and dark themes; diff counts keep at least 4.5:1. Pull request badge colors remain the same. Context menus close existing hover hints and keep hints hidden until the menu closes. A section toggle updates the next Expand or Collapse hint. Star, Refresh and other actions that keep the current pane return keyboard input there; opening a terminal or review keeps focus at the destination. Create one-level project sections with the folder-plus button beside Projects. Rename or delete a section from its menu; deleting moves its projects to Uncategorized. Drag section headers to reorder sections, and project headers to reorder or move projects; a project menu also offers Move to section. Empty and collapsed section headers remain drop targets. New projects go to Uncategorized; dropping a folder directly on a section adds it there, retaining the plain-folder choice. With no user sections the original flat list is shown. Starred stays above the user sections. Project and section order, membership and collapse state survive restarts. The registered project count has a separate badge and a projects tooltip. Application control and child-state icons use vectors independent of the terminal Nerd Font. Claude Code and Codex rows without a confirmed session ID show a neutral, noninteractive icon in the same slot until the provider reports the ID; no other providers receive pictures. Pictures are hidden below 200px. Working uses three small dots that brighten in sequence without changing row height. GPUI animates them from a shared clock, and reduce-motion or macOS Reduce Motion keeps them still. The fixed-width activity-age slot stays empty for Working, unknown times and activity less than one minute ago; otherwise it shows compact ages such as 1m, 2m and 1h.
WorktreesCreate from a new or existing branch, delete with a safety check, merge-and-clean, bulk cleanup of merged branches, update a branch from its upstream when it is clean and no agent works in it (fast-forward; a diverged branch asks before a rebase or merge and never rewrites pushed commits); a note per branch saying what the task is (right-click "Edit note...", or chda note <text> inside the worktree), shown as the row's label and searchable in the palette Creation and note forms share labeled fields, a multiline note area, readable destination/context, explicit Cancel/Create/Save buttons and busy/error feedback. Cmd-V and Edit > Paste insert at the caret or replace selected text, including Unicode notes; single-line branch input flattens line breaks without submitting. Worktree preparation in the repository menu starts with empty command and file lists. Save ordered commands and explicit relative paths without executing them. First or changed plans show the actual new working directory, source/destination paths and steps for confirmation; imported settings never grant permission. Only untracked gitignored regular files are copied, through directory handles that reject symlinks and path traversal. Copies are independent and never overwrite existing files. Setup runs off the UI thread in the configured shell, after copying, with stage and exit feedback. Cancel stops owned preparation processes; failures keep the worktree and copied files. Review retry keeps existing regular files and reruns commands from the beginning, or explicitly Skip. Successful background preparation leaves tabs and typing focus alone; Open starts the planned terminal or the existing per-launch agent options. Setup in the title bar reopens hidden runs. Other windows and MCP requests cannot bypass outstanding preparation. Unfinished runs and editors defer session-preserving updates. The Setup menu opens below its badge and stays inside small windows. A rejected copy entry names the relative file and whether it is missing, tracked, not gitignored, a directory or nonregular file, a symlink, or a path outside the source root. View diff keeps UTF-8 file names readable in both the summary and patch headers while retaining the existing pager and base.
Git historyRight-click a repository and choose "View Git tree" for a read-only commit graph with parent connections, subjects, short hashes and local / remote branches, tags and HEAD. History loads in pages as you scroll; refresh or retry without opening a shell. One graph tab per repository; graph tabs restore after a restart.
Diff reviewOne native review tab per worktree keeps the existing diff pager available. Browse a unified diff with old/new line numbers and a file list that collapses in narrow windows. Added, removed and context lines follow the active light or dark theme, with readable text on selected rows. Shift-click selects a range within one hunk. Add, edit and resolve local notes. Exact unchanged context reconnects after refresh; missing or ambiguous locations stay Stale and require explicit reattachment. Renames keep both path identities; binary and metadata-only changes have no text anchors. Notes persist privately across restarts; failed saves keep editable drafts. Send review notes previews selected notes against a freshly read diff, including original locations for stale notes. Choose an exact live provider/conversation in the same Git worktree. Copy and go to agent rechecks the diff, notes and target, copies plain text and focuses its pane. Paste manually; direct delivery is unavailable. Working and approval-waiting input is never cleared, pasted into or automatically submitted. Copying does not resolve notes or claim delivery; changed conversations block the copy. Open editors and previews defer session-preserving updates.
AgentsClaude Code, Codex, Gemini CLI, GitHub Copilot CLI, OpenCode and MiniMax Code status from their own hooks on tabs, the Sessions list, worktree rows and the Dock badge; notifications that open the agent's pane; jump to the agent that waits (cmd-shift-a); supported historical session lists ordered by the last message, with token usage where available and one-click resume; Codex saved conversations remain available in the resume list with accurate user-message counts; cmd-click several sessions to resume them side by side in one tab; managed Claude Code and Codex launches show Use CLI configuration (the default) or explicit Bypass before starting, including presets, selected conversations and worktree default actions. Codex Bypass disables approvals and sandboxing. Codex launched from chda's menu or typed in its shells stays in its pane without Codex's shared background server and starts without warning about it. Conflicting preset permission options stop the launch without rewriting the preset. Captured executable, working directory, options and permission choice follow the exact conversation on resume and restore; inherited effective policy is shown as unobserved. A managed agent that exits successfully closes its pane; when it fails, its pane shows the exit state and retains the last run as read-only Previous run output; agents that return to a surviving shell keep that same shell. An exact managed-agent restart uses the same pane, confirmed conversation directory, executable, options, permission choice and exact verified conversation; repeated clicks start one successor. Missing executable, directory or transcript produces an error instead of a fresh conversation. A provider without verifiable local transcripts explains that exact resume is unavailable. Live turn completion and commands typed directly in a surviving shell do not offer restart. Stopped panes and previous output survive cold restart and session-preserving updates; available account reports are retained as reports, with CLI authentication inherited. Provider-confirmed Claude and Codex children show on their exact parent's Sessions row, also after the parent becomes idle, as small counts with icons: working, waiting for input in the waiting color, unknown and all children, with no extra line. Hover names the agent and the counts; right-click lists each child with its label, state and report age, and choosing one opens only its exact known dedicated pane or else its status details. Agent rows show the agent's short label in its color, such as CC or CX. Claude child hooks omit prompts and answers; Codex queries the existing local CLI daemon through its WebSocket byte proxy with exact parent IDs and metadata only. Unavailable or unloaded runtime state remains unknown without replacing a reported turn completion or end, and unknown children are counted separately. Codex does not report a running child's live status to chda, so such a child shows unknown. Older CLIs retain their existing top-level behavior. Children do not add usage a second time. Cold restart clears child activity; session-preserving updates retain the reports. On the launch sheet, Up and Down select the permission policy; Tab and Shift-Tab move between editable permission groups, Cancel and Start. Enter or Space activates the focused button. Cancelling returns input to the original pane; confirmation keys are consumed by the sheet. Through chda mcp, agents list their repository's sessions, read a shell's output or another agent's latest answer, and wait for a reported state across windows without moving focus or stopping live sessions. Requests observe preceding hook updates. Linux AppImage hooks, MCP and status-line helpers use a private launcher for the original package so saved commands survive temporary mount removal and restart. Concurrent helpers keep their extraction directories separate from the running app. Gemini CLI and MiniMax Code join Claude Code and Codex in the default menus and palette; explicit user agent lists keep their contents and order. MiniMax launches mcode 0.6.12 or later and needs Node.js on PATH. Its managed launch installs a chda-owned local status plugin, preserving other plugins, user config and a disabled plugin state. Private pane routing keeps simultaneous MiniMax conversations separate; unmanaged launches report nothing. MiniMax historical conversation indexing, exact resume, restart, token usage and child summaries are unavailable in this initial integration.
Status barThe bottom bar reports provider quota, never inferred from token counts. Startup shows Waiting for usage for Claude Code and Loading for Codex. Claude readings follow the focused session's configuration folder, so a session that has not answered yet shows the same sign-in's newest reading, and the last reading per folder returns after a restart marked previous run. Empty reports preserve the same session or account's last valid reading and its actual age. Claude usage updates keep other windows and their live sessions running. All windows share reports and one Codex query loop; transient failures retry promptly, and a verified account's retained reading is labeled retrying. Authentication and installation problems have specific labels and details. Claude Code reports through a per-launch status line; Codex uses the local app-server account protocol. Details separate accounts or unknown session scopes and quota windows. On macOS, selected-pane PTY descendants supply CPU, summed RSS, listening endpoints, process count and uptime. Sampling runs off the UI thread with deadlines. See docs/status-bar.md for scopes and refresh behavior. Click either provider to open details above the bottom-left controls. Each reported quota window has a labeled 0–100% bar, value and reset time; scope, source, observed age, historical reports and errors stay distinct. Unknown data creates no bar. Content scrolls inside the window. Escape or the close button dismisses the details popup and returns typing focus to its original pane. Linux samples process resources and listening TCP or unconnected UDP sockets through /proc, including IPv6, without requiring lsof.
Palettecmd-shift-p: every action, worktree, agent launch and session in one fuzzy list On Linux, Settings, Ghostty config, window actions, terminal copy/paste/search, About, help links and Quit are also available from the palette. Linux opens it with Ctrl+Shift+P or the Commands button. The Linux About dialog shows the version, full description, license and repository link at default and narrow window sizes. The list fits small windows, scrolls to the selected action during keyboard navigation and keeps it visible after resizing. An open palette keeps keyboard input when its window reactivates after resizing.
ConfigReads your Ghostty font, colors and padding; chda's own settings in one TOML file; edits apply without a restart; executable discovery uses the login-shell PATH, with a validated ~/.local/bin/claude fallback for native Claude Code installations. Live configuration reload keeps the current sidebar width while its border is being dragged; other settings still apply, and file-based width changes apply again after release. Define your own [[commands]], such as lazygit, a test watcher or a dev server, and run them for the focused worktree from the palette, a worktree's menu or a shortcut, in a new tab, a split or a floating terminal; each closes when the command succeeds and keeps a failure's exit status; broken entries and clashing shortcuts are reported once while the rest load. A theme pair, theme = light:X,dark:Y in the Ghostty config or chda's theme, follows macOS Light and Dark mode in every window without a restart, including Auto at sunset; View > Select Light Theme and Select Dark Theme each preview and save one half while keeping the other. Reading configuration or repository state on Linux does not trigger repeated reloads or sidebar refreshes. Set reduce-motion = true to keep non-essential animations still on every platform; macOS also follows its Reduce Motion preference. Project sections use persistent ids in project-sections and path-to-id membership in repo-sections; repos remains the project registration and ordering list. Older configs and missing section ids show their projects as Uncategorized.
Linux desktopLinux x86_64 packages share the same payload, target glibc 2.31 or newer, and use the host graphics driver. X11 and Wayland window controls, XDG folder applications, pane-targeted desktop notifications, foreground process directories and process resource inspection integrate with the terminal. Updates open the matching stable Linux release for a manual download; configuration and saved sessions remain outside the package. See docs/linux.md for installation and verified environment limits.

Sessions keeps its rows in tab and pane order, so concurrent output and status changes never move them. An agent row stands for one agent pane, busy or idle; plain shells and saved conversations are not agents, and ordinary terminal tabs come last. The right edge shows time since the latest terminal activity (1s, 1m, 1h, 1d; — when unknown). This measures terminal output and delivered input, not whether an agent is thinking; theme changes, resizing, selection, searching and scrolling do not reset it. Hover the age of an idle agent for how long it has been ready. Hover a status icon for its state in words. Click Alias / Branch in the Sessions header to switch between each branch note's first line and its branch name. Missing notes fall back to branch names; the choice is saved, and hovering shows the repository and branch.

Click a row to focus that exact pane or tab. Its branch is highlighted in PROJECT, which scrolls only as far as needed to show it; the Sessions list itself never scrolls on its own. The close button on a terminal row closes that tab, and on an idle agent's row only that pane.

How agent status works

chda is the hook. When it launches Claude Code it passes a per-session --settings file that registers chda hook claude for session start, prompt submit, permission requests, stop and session end. Codex gets -c notify=[...] pointing at chda hook codex; if you already use a notify program, chda runs it after its own. Codex status also comes from its terminal title, with a per-launch tui.terminal_title override. In chda's zsh, bash and fish shells, typing codex directly gets that title override too: each turn shows working, requests for user input show waiting, and returning to the shell clears the status. Existing codex aliases/functions are kept; shell integration must be enabled, and command codex or an absolute CLI path bypasses the helper. The title format is verified against Codex 0.160.0; a CLI without these title items cannot report this way. Codex 0.156 and later cannot take per-launch overrides into their shared background server, so these launches run Codex in the pane itself, as before; chda also passes features.daemon_auto_start=false so Codex does not warn about that at every start. Older CLIs ignore the setting. Gemini CLI gets GEMINI_CLI_SYSTEM_DEFAULTS_PATH pointing at a copy of your machine's system defaults with chda's hooks added (Gemini CLI concatenates hooks from all settings layers). MiniMax Code runs mcode 0.6.12 or later and requires Node.js on PATH. On a managed launch, chda installs its own chda-status local plugin in the active MiniMax data directory (MINIMAX_DATA_DIR, then MAVIS_DATA_DIR, otherwise ~/.minimax). For a profile, supply its explicit data directory. This preserves MiniMax configuration, other plugins and plugin enablement. Modified or conflicting plugin files stop the launch and are preserved. A disabled plugin stays disabled; enable it yourself with mcode plugin enable chda-status@local if you want status reporting. A private directory on each managed launch's PATH carries its pane routing because MiniMax drops custom hook environment variables. Outside a managed launch the plugin reports nothing, including when you type mcode directly into a shell. GitHub Copilot CLI gets --plugin-dir with a local plugin whose hooks call chda hook copilot. OpenCode gets OPENCODE_CONFIG_DIR with a plugin that reports session status to chda hook opencode; if you set OPENCODE_CONFIG_DIR yourself, chda leaves it alone and OpenCode reports nothing. The hook forwards only the session id, working directory, event kind, a timestamp and the chda pane it runs in (from CHDA_PANE_ID, which every chda shell sets) to the running app over a local socket. Prompt text and transcripts are never stored. None of the agents' own settings files (~/.claude/settings.json, ~/.codex/config.toml, ~/.gemini/settings.json, ~/.copilot, ~/.config/opencode) are modified.

At most once a day, chda checks public GitHub release information. Linux selects the latest stable release containing a Linux package; macOS checks api.github.com/repos/magicsih/chda/releases/latest. No local session data is attached to either request. update-check = false disables that check. In a configured, signed macOS release, click Update to x.y.z to download, verify and install through Sparkle. Progress is shared across windows; administrator approval uses the macOS system dialog. Release notes and dismissal are in the adjacent menu. Downloads and installation never start automatically. Linux opens the matching release page for a manual package update, keeping running shells alive.

Windows briefly reopen while the same shells and agents reconnect with their terminal text, scrollback, layouts and focus. A failed installation or new-app startup reopens the retained signed app with those sessions. Terminals that have used inline images block the update without stopping their processes; close those terminals before trying again. v0.1.19 users need one manual update to the first updater-enabled release: brew upgrade --cask --greedy chda, or download the latest release. See the update decision for release signing requirements and validation boundaries.

Past sessions are listed under each worktree for Claude Code, Codex, Gemini CLI and Copilot CLI. OpenCode keeps its sessions in a database chda does not read. MiniMax currently supports managed launches and live status; chda does not index its past conversations or offer exact resume, restart or usage reports.

Claude Code and Codex sessions show the tokens they used. The tooltip breaks them down (input, cache writes, cache reads, output, subagents included) and estimates what the same work would cost at API list prices; subscriptions are not billed per token, so read it as a measure of size, not a bill. Codex sessions also show how much of the plan's rate limit was used at the last turn.

Agents can drive chda (MCP)

chda mcp is an MCP server that lets an agent work with the chda window it runs in: create_worktree (new branch and folder, optional base, note and agent to start in a new tab), open_tab, list_worktrees, and report_status (working, waiting for input, done) for agents without hooks. It acts through the running app, so new worktrees follow your worktree-path-template and show up in the sidebar at once.

A coordinating agent can also follow the helpers it started, read-only and only in its own repository: list_sessions (agents and terminals with pane id, status, worktree, branch, last activity and child counts), read_output (a Claude Code or Codex session's latest answers from its transcript, or a shell's screen up to its prompt; never what you are still typing) and wait_for_status (until an agent's turn completes, it waits for input, its pane closes or up to 55 seconds pass). These calls never move focus or change what the sidebar shows. Add the server once per agent:

claude mcp add --scope user chda -- chda mcp
codex mcp add chda -- chda mcp
gemini mcp add --scope user chda chda mcp
copilot mcp add chda -- chda mcp

For OpenCode, add "mcp": {"chda": {"type": "local", "command": ["chda", "mcp"]}} to ~/.config/opencode/opencode.json.

Configuration

chda reads Ghostty's config files in Ghostty's order: ~/.config/ghostty/config and config.ghostty, then on macOS the same two in ~/Library/Application Support/com.mitchellh.ghostty. It honors font-family, font-size, font-feature, theme, background, foreground, palette, cursor-style, cursor-style-blink, window-padding-x/y, shell-integration and scrollback-limit, so a Ghostty user gets the same look without copying anything. Like Ghostty, chda ships JetBrains Mono as the default font and Symbols Nerd Font Mono for prompt and TUI icons.

Programming ligatures (->, !=, >= in JetBrains Mono, Fira Code and similar fonts) are off by default. Turn them on with font-feature = calt; font-feature takes Ghostty's syntax (-liga, ss01, cv01=2, repeated or comma-separated). The character under the cursor is always drawn on its own.

chda's own settings live in ~/.config/chda/config.toml:

repos = ["/path/to/repo"]
worktree-path-template = "{repo_parent}/{repo_name}.worktrees/{branch}"
default-action = "terminal"   # terminal | claude | codex | gemini | minimax | copilot | opencode
tab-title = "branch"          # branch | path
active-label = "alias"        # alias | branch; Sessions header toggle, saved across restarts
agents = ["claude", "codex", "gemini", "minimax"] # add "copilot", "opencode"
sidebar-width = 280           # also set by dragging the sidebar's border; double-click resets
sidebar-visible = true
sessions-collapsed = false    # Sessions header toggle, saved across restarts
project-collapsed = false     # PROJECT header toggle, saved across restarts
notifications = true
restore-session = true        # reopen the last tabs, splits and directories
restore-agents = true         # ...and the agent conversations those panes had open
editor = "zed {file}:{line}:{column}"  # opens cmd-clicked paths; unset: default app
theme = "Catppuccin Mocha"    # replaces the Ghostty config's theme; unset: follow it
pull = "ff-only"              # ff-only | rebase | merge: "Update branch" on a diverged branch
open-in = "vscode"            # the title bar's app; set by picking one there
update-check = true           # ask GitHub once a day whether a newer release is out

[repo-hosts]                  # pull request host when the remote does not say
"/path/to/repo" = "github.example.com"

# Named agent launches, in a worktree's right-click menu and the palette
[[agent-presets]]
name = "Claude Opus"
agent = "claude"              # claude | codex | gemini | minimax | copilot | opencode
args = ["--model", "opus"]    # added after chda's hook arguments

[[agent-presets]]
name = "Codex full auto"
agent = "codex"
args = ["--full-auto"]

# Your own commands for the focused worktree, from the palette ("Run lazygit"),
# a worktree's right-click menu or a shortcut
[[commands]]
name = "lazygit"
run = "lazygit"               # through your login shell, in the worktree
open = "floating"             # tab (default) | split | floating
key = "cmd-shift-l"           # optional; built-in shortcuts keep theirs

A floating command opens over the window and closes when it succeeds; when it fails it stays with its exit status until Escape or cmd-w. While it runs, Escape goes to the program, and cmd-w twice stops it. Commands run only when you start them, and only this file defines them. A broken entry or a clashing shortcut is reported once in the title-bar notifications; the other commands still load.

"Select theme..." in the command palette lists the 650+ themes chda bundles (the iTerm2-Color-Schemes set Ghostty ships) plus any in ~/.config/ghostty/themes. The arrow keys preview each one; enter saves it as theme in config.toml, esc puts the previous one back. "Select light theme..." and "Select dark theme..." set one half of theme = "light:X,dark:Y", which follows macOS Light and Dark mode.

Both files are watched: saving one updates open windows within a second. A value Ghostty would reject keeps the previous settings and shows a message.

Keyboard shortcuts

KeysAction
cmd-t / cmd-wnew tab / close pane
cmd-1…cmd-9, cmd-0select the first ten Sessions rows
cmd-shift-[ ]switch tabs within the repository
cmd-d / cmd-shift-dsplit right / down
cmd-alt-arrows, cmd-[ ]move between splits
cmd-ctrl-arrows, cmd-ctrl-=resize / equalize splits
cmd-shift-enterzoom a split
cmd-up / cmd-downprevious / next shell prompt
cmd-fsearch the scrollback; enter / shift-enter older / newer, alt-c case, alt-r regex, esc close
cmd-clickopen a link or file path (hold cmd to see it underlined: solid for files, dotted for folders)
drop files on a pane / a folder on the sidebarpaste the quoted paths / add the folder as a repository
right-click a pathopen, reveal in Finder, open a tab or cd there, copy the absolute or relative path, preview a Markdown file (cmd-shift-click in apps that read the mouse)
cmd-= / cmd-- / cmd-alt-0bigger / smaller / configured font size
cmd-shift-ago to the agent that waits for input, then to finished turns
cmd-btoggle the sidebar (also the button next to the window buttons)
cmd-shift-oadd a repository
cmd-nnew worktree
cmd-shift-pcommand palette
cmd-c / cmd-vcopy selection / paste
cmd-, / cmd-shift-,open config.toml / reload both configs
cmd-m, cmd-h, cmd-alt-hminimize, hide chda, hide others

On macOS, actions also appear in the menu bar, with agent launches and session resume under Agents. On Linux, use the Commands button or Ctrl+Shift+P. See Linux shortcuts for platform bindings.

Status and roadmap

chda runs on macOS, Apple silicon and Intel, and Linux x86_64 with X11 or Wayland. Linux packages share one payload and require glibc 2.31 or newer and a compatible graphics driver. Windows continues to build in CI; its desktop release remains planned. See docs/roadmap.md and CHANGELOG.md.

FAQ

How is this different from Ghostty? Ghostty is the terminal; chda borrows its core and adds the worktree sidebar and agent status board. If you do not run several worktrees at once, Ghostty is the better terminal.

Intel Mac? Yes. The release is a universal app with an Intel build inside.

macOS says the app is damaged or from an unidentified developer. Releases are signed and notarized, so this should not happen. If it does, you probably have a build from somewhere else; download the zip from the releases page.

Do I need gh? No. Without it you lose only the pull request badges. Each repository asks the host of its remote: gh for GitHub and GitHub Enterprise Server, glab for GitLab, tea for Gitea and Forgejo (Codeberg). github.com, gitlab.com, gitea.com and codeberg.org are recognized by name; any other host goes to whichever of the three is logged in to it. SSH aliases from ~/.ssh/config are resolved with ssh -G. A repository whose host is not logged in shows the command to run instead of badges.

Agents missing when launched from the Dock? chda reads the PATH from your login shell's startup files at launch and uses it for both agent detection and terminal processes. This includes Homebrew, npm and version-manager locations configured in zsh, bash or fish. Restart chda after changing that PATH. If the shell takes longer than two seconds, chda keeps reading it in the background for up to 20 seconds, retries after 30 seconds, 2 minutes and then every 10 minutes, and starts or restores agents once it arrives. Until then the inherited PATH applies, and the Codex usage meter says Could not read the shell PATH with the directories it searched.

Other shells? Status, directory tracking and prompt jumping come from shell integration for zsh, bash and fish. Other shells fall back to polling the shell's working directory; prompt marks are missing there.

Contributing

See CONTRIBUTING.md for the build setup (Rust, Zig 0.16.0, Xcode) and docs/architecture.md for the crate layout. Bugs and ideas go to issues.

Acknowledgements

Ghostty for libghostty-vt, Zed for GPUI, and Ghostree for showing that a worktree sidebar belongs inside the terminal.

License

MIT. The bundled fonts keep their own licenses: JetBrains Mono under the SIL Open Font License 1.1 and Symbols Nerd Font under MIT; both texts are in crates/chda-ui/assets/fonts. The bundled themes come from iTerm2-Color-Schemes under MIT (crates/chda-config/assets/themes-LICENSE.txt). Markdown previews use pulldown-cmark under MIT. The diagram viewer bundles Mermaid 12.1.0 under MIT (crates/chda-ui/assets/mermaid/LICENSE).

↑↓ navigate openesc close