All documentation

Every documentation page on one scrolling page — built for Ctrl+F, for linking straight to a section, and for pasting into a coding agent's context. Each section links back to its own page, which is the canonical one to share.

Getting started

https://termhq.dev/docs/getting-started/

Open your first terminals, tile them, and learn the handful of shortcuts that matter.

A new workspace starts with a single terminal running your default shell. After that, launching TermHQ resumes the workspace you were last in — panes, shells, directories and layout — rather than starting over. You can change that in Settings → Workspaces → On startup, or pick a different workspace from the picker every time.

Everything else is built on two ideas: panes are tiled rather than stacked, and the shells inside them are not owned by the window.

Your first panes

The + button in the title bar opens another pane running your default shell. Its caret opens a list of every shell TermHQ found on your machine: PowerShell 7, Windows PowerShell, Command Prompt, Git Bash and each WSL distribution on Windows; whatever /etc/shells reports on macOS. Once Settings → SSH → SSH connections is on, the same list ends with Connect via SSH…, which opens a connection to another machine as a pane — see SSH connections.

Panes tile automatically — with two open you get two columns, with four you get a 2×2 grid. Open as many as you like; there is no limit, and the grid grows to hold them. Drag the space between two panes to change how the room is divided.

Not every pane has to be a shell. The globe in the title bar — or Ctrl+Shift+B — opens a browser pane, a real web page tiled beside your terminals. Ctrl+Shift+E opens an editor pane, which holds files as tabs. Both take the same header and the same moves as a terminal.

With no panes open, the start panel offers New terminal, Find a command, Workspaces, and your favorite directories. If your panes are all stashed, it points you back to the shelf. Workspace selection also lives at the far right of the bottom status bar, beside Stash.

Make the interface comfortable

In Settings → Appearance, choose Compact or Comfortable interface density and scale the app’s labels and controls from 100% to 150%. Terminal and editor text keep their own size settings, and these options work with every theme.

The same page can put a picture, a GIF or a looping video behind your terminals. Background keeps a small library — Add… copies a file in — and Transparency (25% by default), Blur, Fit and, for a video, Speed tune it. The text stays solid at any setting, and the background is the same in every workspace, like the theme.

Two more switches live there. Dim unfocused panes, off by default, washes every pane but the one you are typing into toward the background. Animate panes, on by default, lets panes glide, fly and fade as they move; turn it off and they jump straight into place.

Need a little more room for file names or Git changes? Drag the sidebar’s inner edge to widen it. Its original width is the minimum, the maximum is bounded, and a double-click on that edge resets it. See Configuration for keyboard controls.

Layouts

Two presets live in the title bar:

  • Grid — kept square-ish. Four panes make a 2×2, five to nine go three wide, ten to sixteen go four wide, and onwards from there.
  • Columns — every terminal a full-height strip.

Each workspace remembers which of the two it uses.

Panes can also be dragged by their headers to move, swap and grow, or rearranged entirely from the keyboard. See Panes and layout.

The shortcuts worth learning first

Action Shortcut
New terminal Ctrl+J
New browser pane Ctrl+Shift+B
New editor pane Ctrl+Shift+E
Delete the focused terminal Ctrl+Shift+D
Move focus between panes Ctrl+Shift+arrow
Command palette Ctrl+Shift+P
Settings, with search focused Ctrl+P
Workspace picker Ctrl+Shift+W
Jump to the newest waiting pane Ctrl+Shift+N

If you only learn one, learn the command palette: it lists every action by name with its shortcut beside it, so the rest do not have to be memorized first. It also opens your favorite folders, shells, agents, other workspaces, saved and recent SSH targets (once SSH is on), themes and Settings pages, and with nothing typed it leads with what you ran recently.

On macOS, ⌘ replaces Ctrl throughout — except dictation. Every one of these is rebindable; see Keyboard shortcuts for the full list and why the app-level chords are three keys rather than two.

Copy and paste

Selecting text and pressing Ctrl+C copies it. With nothing selected, the same key sends the interrupt to the running program, as it should. This is the behavior Windows Terminal uses. Ctrl+Shift+C copies unconditionally.

Paste is Ctrl+V, Ctrl+Shift+V or Shift+Insert. What a right-click does is up to Settings → Terminal → Right-click in a terminal. The default, Automatic, opens a menu on macOS — Copy, Paste, Select all, Clear and Find — and on Windows copies the selection if there is one and pastes if there is not. Either behavior can be chosen on any platform.

Dropping a file onto a terminal types its path at the prompt, quoted the way that shell reads quotes. Files can come from your file manager or from the Files panel. Dropped on an editor pane, a file opens there instead; a browser pane, an SSH pane or a terminal whose shell has ended refuses the drop and says why.

A web address in a terminal’s output opens with Ctrl+click (⌘+click on macOS), in your default browser. Add Shift to open it in a browser pane beside the terminal instead. A plain click only focuses the pane, so a link an agent printed never opens by accident.

Installation

https://termhq.dev/docs/installation/

Install TermHQ on Windows or macOS, what to expect from SmartScreen and Gatekeeper, and how updates work.

Download the build for your platform from the releases page.

Windows

Run the installer. TermHQ supports Windows 10 and 11.

Because builds are not yet code-signed with an Authenticode certificate, SmartScreen shows a warning the first time you run an installer: “Windows protected your PC.” Choose More info → Run anyway. SmartScreen judges each file separately, so the warning can reappear when you install a new version — same two clicks. Why the warnings →

There is nothing to install alongside it — no runtime, no separate terminal components. TermHQ carries its own copy of the Windows console machinery, which is why terminals render identically on an old Windows 10 build and a current Windows 11 one. Some terminal apps do not, and the difference shows up as duplicated prompt lines in exactly the full-screen tools coding agents use.

macOS

Open the .dmg and drag TermHQ to Applications. Builds are for Apple silicon; there is no Intel build.

From v0.2.3, the app bundle has an ad-hoc signature that macOS can verify for integrity. It is not signed with an Apple Developer ID or notarized by Apple, so Gatekeeper still requires approval. On current macOS (Sequoia and later), use System Settings for the first launch:

  1. Open TermHQ once. macOS says it “could not verify this app is free of malware” — dismiss the dialog (don’t choose Move to Trash).
  2. Open System Settings → Privacy & Security, scroll down to the Security section, and click Open Anyway next to the TermHQ message.
  3. Confirm in the dialog that follows. From then on it opens normally.

On older macOS versions, right-click → Open still offers an “Open” button directly. Why the warnings →

If v0.2.2 says TermHQ is damaged

Download v0.2.3 or later and replace the older TermHQ app in Applications. The v0.2.2 macOS bundle had an incomplete code signature; v0.2.3 fixes that packaging defect. Your settings and saved workspaces live outside the app and are preserved when you replace it. Follow the approval steps above after installing the new version.

Why the install warnings

TermHQ does not yet use verified publisher certificates: the Windows installer has no Authenticode certificate, and the macOS app uses an ad-hoc signature without Apple notarization. The macOS signature seals the app’s contents but does not establish an Apple-verified publisher identity. That is why explicit approval is still required even when the bundle passes signature verification.

Two things worth knowing in the meantime:

  • Download only from this site or the releases page — every build is published from an exact tagged commit, so a version always means the same code.
  • If a downloaded installer vanishes, an antivirus false positive is the likely cause — unsigned binaries occasionally trip them. The file on the releases page is unchanged; restore it from quarantine or re-download.

Linux

Linux support is pending.

Voice dictation

Dictation runs on local Whisper models: transcription happens on your own machine.

The installers ship without a speech model, which is most of why they are small. The first time you want voice, open Settings → Voice and download a model — one click, a progress bar, done. Until then there is no mic button and nothing voice-related runs: nobody gets handed a hundred-megabyte AI download they did not ask for. On macOS the first recording asks for microphone permission, as any app does.

Four models are offered, from a quick 78 MB English-only one to a 1.6 GB multilingual one — each labeled with its size and language coverage, and the panel says in plain text exactly where every download comes from. Models can be switched, deleted, or re-downloaded at any time, they survive app updates, and if you already have a compatible model file of your own, Import brings it in instead.

Dictation listens in English by default. Settings → Voice has a language dropdown with sixteen more, plus an auto-detect option that lets a multilingual model identify the language per recording.

How dictation works day to day — the mic button, the chord, Hold to talk, where the words land — is on the Dictation page.

Where TermHQ keeps its files

Settings, themes, saved workspaces and a log file live in a per-user configuration directory, along with the pictures and videos you add as backgrounds (backgrounds/) and your saved SSH profiles and recent connections (ssh-profiles.json, which never holds a password or a key):

Platform Path
Windows %APPDATA%\dev.termhq.app
macOS ~/Library/Application Support/dev.termhq.app
Linux ~/.config/dev.termhq.app

If config.json there ever cannot be read — a typo in a hand edit, say — TermHQ keeps a copy of it named config.json.broken- plus the time in UTC, such as config.json.broken-2026-09-23T101500Z, starts with default settings, and shows a notice with the reason and a button that opens the folder.

Updating

TermHQ checks for a new release on its own — shortly after launch and every six hours while it runs — and never installs one on its own. A new version shows up in two places: a toast at the bottom left of the window, and Settings → General → Updates. Both have one button, Update and restart; the toast also has Later, which puts that version away until a newer one comes along or the next launch, and What’s new, which opens Settings → General → Updates, where the release notes are.

What the click does, in order: the release is downloaded and its signature checked; any editor with unsaved changes asks you to save or discard, the same protection as closing the window; if terminals are running in any workspace, TermHQ asks Update and restart now? and says how many will end; other TermHQ windows are asked to close and take the same card; then TermHQ closes, the installer runs, and TermHQ reopens in the workspace you were in.

The unsaved-work check happens after the download, so it includes edits you made while waiting. Choose Save all & update, Update without saving, or Cancel. If another window remains open, check it for a save prompt, close it when ready, and try the update again. TermHQ does not force it closed.

The terminals question counts every workspace, not only the window you clicked in, because the restart ends the shells in all of them, along with the commands and agents running there. Cancel has focus, so Enter alone backs out; Update and restart goes ahead.

Update signatures verify that the download comes from TermHQ. They are separate from the operating system’s installer certificates, so the installation warnings described above may still appear.

Your shells restart. The layout, working directories, titles and the stash all come back; commands and agents that were running in those panes are stopped. The toast says so before you click. Your configuration directory is never touched by an update: settings, themes, keyboard shortcuts, favorites, saved workspaces, backgrounds, SSH profiles and speech models all stay exactly as they were.

If a download fails or its signature does not verify, nothing is installed and the app stays as it was; the toast offers to try again. Turn the automatic check off in Settings → General → Updates and “Check now” becomes the only way to look. Installing over the top from a downloaded release works too, and leaves the configuration directory alone just the same.

If TermHQ cannot save the workspace, installation stops before shutting down your shells. If the installer fails after the shells have stopped, the app reports the failure and restores the ability to open terminals for recovery. Previously running commands have still stopped; check your work before retrying.

Uninstalling

Use the platform’s normal uninstall route. The configuration directory above is left in place; delete it by hand if you want TermHQ’s settings, themes, saved workspaces, backgrounds and SSH profiles gone too.

Panes and layout

https://termhq.dev/docs/panes-and-layout/

Tiling, the slot grid, resizing by the gutter, keyboard arranging, maximizing, pane motion, stashing, and undoing a close.

Everything TermHQ opens is a pane in a tiled grid. Nothing hides behind a tab.

There are three kinds, and the grid treats them identically — every move below works on any of them:

Pane Opens with Holds
Terminal Ctrl+J A shell
Browser Ctrl+Shift+B A web page
Editor Ctrl+Shift+E Files, as tabs

An SSH connection opens as a terminal pane too, once you turn SSH on in Settings → SSH → SSH connections; it is off by default.

The slot grid

Every pane occupies a rectangle of grid cells. Move, swap, and grow panes to arrange your workspace; opening and closing panes can repack the grid to fit.

That is the arrangement. How wide each cell is, is a separate and much simpler question — see Resizing panes below.

There is no limit on how many terminals you can open. The grid keeps growing to hold them, and two presets in the title bar decide the shape:

  • Grid — kept square-ish. Four panes make a 2×2, five to nine go three wide, ten to sixteen go four wide, and so on.
  • Columns — every pane is a full-height strip, however many there are.

Each workspace keeps its own choice, and switching keeps the panes in the order you read them. Switch between Grid and Columns does it from the keyboard once you give it a shortcut in Settings → Shortcuts.

When the columns no longer fit the window, the grid scrolls sideways rather than squeezing them. A window too narrow for both the sidebar and the grid closes the sidebar first, and opens it again once there is room, without changing your sidebar setting.

Past the point where everything still fits comfortably, the answer is usually to park what you are not watching on the shelf, or fill the screen with one pane — both below, and neither stops anything running.

Panes also fall upward: a pane rises until it rests on the top edge or on another pane. That is what makes floating islands and phantom rows impossible, so resizing the window always divides the space over real rows.

A single terminal fills the whole grid area rather than sitting in one half-width cell. Spawning or cloning splits it back into the grid.

In Grid, an empty cell offers New terminal and Open file…, and whatever you open from one lands in that cell.

Pane style

The grid has two looks, chosen in Settings → Appearance → Pane style. Spaced, the default, keeps a small gutter between terminals and rounds their corners. Boxy removes both — terminals meet edge to edge with square corners, the tiling-window-manager look. Borders stay on in either style, so two terminals never blur into one, and switching is instant: no pane reflows or resizes, only the chrome around it changes.

Either way, the boundary between two panes is a resize handle; boxy simply puts it on the seam where they meet instead of in a gutter.

Settings → Appearance → Dim unfocused panes washes every pane but the focused one toward the theme’s background, so the one you are typing into stands out. It is off by default, and clicks still reach the dimmed panes.

Pane motion

Panes move rather than jump. When they swap, move or resize, they glide into place. A new pane settles into its cell with a quick fade while the others glide aside, and a closed pane fades from its place as the grid closes up under it. Stashing flies a pane down into the shelf’s count, which bumps as it lands, and restoring one rises back out into its cell. Maximize grows a pane from its cell until it fills the grid, and Restore shrinks it back. The sidebar slides in and out while the panes glide beside it, and a workspace appears in one fade, already laid out.

Settings → Appearance → Animate panes turns all of it off. It is on by default; off, panes jump straight to where they go. Reduced motion in your system settings turns it off too.

The pane header

Every header starts with a mark that says what the pane is: a prompt for a terminal, a globe for a browser, a page for an editor. It lights on the focused pane and pulses in the attention color when a run goes quiet. The focused pane keeps its header buttons in view; the others show theirs when you hover.

A terminal’s header shows its whole working directory. When the path does not fit, the start gives way first and the folder’s own name stays. Hover the path to read all of it, and click its text to copy it.

  • Double-click the header, name included, to maximize the pane.
  • Middle-click the header (click the scroll wheel) to close the pane, as on a browser tab. It closes exactly the way the header’s own close button does.
  • Right-click a terminal’s header for Rename…, Copy path, Reveal in File Explorer (Reveal in Finder on macOS), the pane’s own actions, and Close. On a browser or editor pane, a right-click on the header renames it.
  • F2 renames while the keyboard is on the header’s buttons. In the terminal itself, F2 stays with the program. Rename the focused pane does it from anywhere, once you give it a shortcut in Settings → Shortcuts.

Rearranging with the mouse

Drag a pane’s header. A translucent copy of the header follows the pointer, so it stays clear which pane you picked up, and names what letting go would do: Swap, Move here or Grow. A dashed destination preview shows where it will land. Press Esc at any point to cancel.

It is one gesture family, borrowed from Windows snap:

Drop target Result
Onto another pane The two swap places
Into a free cell The pane moves there
Onto the near half of an aligned free cell beyond an edge The pane grows to that cell if the space between is free
Onto a grown pane’s own cell It un-snaps back to that single cell

Closing a pane re-packs the rest in reading order, so middle holes close and the grid shrinks back through square sizes — unless you have hand-grown a pane, which switches to a gentler reflow that does not disturb your arrangement.

Closing or stashing the pane you are in keeps your place: the grid closes up, and the pane that moves into that cell takes the keyboard. Close the sixth pane of a three-wide grid and what was the seventh is selected. If the grid loses a column or a row, the pane in the same corner takes it instead, so closing the top-right pane leaves you top right. When nothing moves in because the last pane went, the one before it does.

Resizing panes

The space between two panes is a handle. Put the pointer on it, the cursor turns into a resize arrow, and dragging moves that boundary wherever you want it — the same gesture as dragging a window edge, and the same one every tiling window manager uses.

Which panes move follows from where the boundary is. Panes with an edge on the boundary you are dragging move with it; panes that do not touch it do not move at all. With three columns open, resizing the first two leaves the third exactly where it was.

Where four panes meet, the crossing is a corner: grab it and both boundaries move at once, diagonally, the way an operating system’s window corner does.

A few things fall out of that:

  • Double-click any boundary — or a corner — to even up the pair it separates. It is the “make this sensible again” gesture, scoped to the edge you clicked rather than resetting the whole grid.
  • A pane can never be dragged out of existence. Columns stop at 280px at 100% interface scale — the floor grows with the scale, to 420px at 150% — and rows stop at 240px, so the boundary refuses rather than tearing.
  • Gutters take the keyboard too. Tab reaches one, the arrow keys move it 24px at a time (96px with Shift), and Enter evens up the pair it separates.
  • Only the boundary under your pointer lights up — a thin line on the one that would move, and the one you are actually holding is a shade brighter still. It waits a moment before appearing, so sweeping the pointer across a gutter on the way somewhere else lights nothing; stop on one and the line is there immediately. Leaving is never delayed.

The gesture is the reason a browser pane and a terminal can share a row honestly: a web page has a natural width and a terminal does not, so 70/30 is often the right answer and 50/50 never was.

Putting it back

Two ways, at two scales. Double-clicking one boundary levels the pair it separates. For the whole grid, a small reset button appears in the title bar beside the Grid/Columns switch.

It is only there when there is something to reset — drag a pane off its equal share and it appears; level the grid again and it goes. That is deliberate on both counts: a button that spends most of its life doing nothing is furniture, and one that shows up only when the grid is custom answers “why is this pane wider than the others?” just by being there. Reset pane sizes does the same from the command palette, or from a shortcut you give it.

Opening or closing a pane resets the sizes

A hand-tuned layout is tuned around the panes that were in it. So opening a new pane — or closing, stashing, or restoring one — puts every boundary back to equal.

Nothing else disturbs them. Swapping, moving, growing, arranging and resizing the window all leave your proportions exactly as you set them, and a workspace remembers them across restarts.

A maximized pane and a lone pane have no boundaries to drag, because there is nothing on the other side of one.

If you would rather the grid simply divided itself evenly, Settings → Appearance → Resize panes by dragging turns the whole thing off: equal shares, no handles. Your proportions are kept while it is off, so switching back on returns the layout you had.

Arranging from the keyboard

Everything the drag can do, without the mouse. Press Ctrl+Shift+G to enter arrange mode, then use the arrow keys. What a press does depends on what is in that direction:

  • Arrow pushes the pane that way: it grows into free space, keeps growing on further presses, or swaps with a neighboring pane. When it cannot advance, it pulls its back edge inward.
  • Shift + arrow moves the pane one cell while keeping its size, where it fits.
  • Ctrl + arrow shrinks it from that direction. On macOS it is ⌘ + arrow, because Ctrl + arrow belongs to Mission Control there.

A size-preserving move toward several smaller panes can swap the entire block when it fits.

You can also bind Push pane left / right / up / down under Settings → Shortcuts → Arrange without the mode. These perform the same push without entering arrange mode and have no default shortcuts.

While the mode is on, the pane you are arranging is outlined, and a hint bar names the mode and previews what each arrow would do from where the pane stands: grow, swap, move or shrink. Esc or Enter finishes, and any other key — or any mouse click — simply leaves the mode and does its usual job, so the arrows are never held hostage once you have moved on.

Panes will not grow past the edges of the grid in any direction, downward included. The chord itself is refused when there would be nothing to watch: a single pane, or a pane already maximized over the others.

Maximize

Ctrl+Shift+Z, a double-click on a pane header, or the header’s Maximize button fills the grid with one pane; the same action restores the grid. Hidden panes stay alive throughout, and moving focus while maximized carries the maximize to the next pane rather than dropping back to the grid.

With pane motion on, the pane grows from its cell until it fills the grid, and Restore shrinks it back into place, with the other panes fading in around it once it lands.

With only one pane in the grid there is nothing to maximize: the chord is refused, and a double-click on the header does nothing.

Font size

Separate from the above, and per-pane. Ctrl+= and Ctrl+- change the focused pane’s font size, Ctrl+0 resets it, and Ctrl+wheel — or a trackpad pinch, which arrives as the same event — changes whichever pane is under the pointer, editor panes included. An agent’s wall of output can be small while the shell you type in stays comfortable.

A terminal shows the size it landed on for a moment, with the way back: 15 px · Ctrl+0 resets.

The status bar

The thin bar along the bottom of the window is always visible. The pane grid ends above it, so items appearing or disappearing do not cover your work or change the space available to panes.

Workspace is at the far right, with Stash immediately beside it when panes are parked. Worktrees appears at the left when you have configured worktree roots. Undo close and the waiting-pane list appear as needed, before Stash and Workspace.

Right after Worktrees — or at the far left without it — the focused pane’s branch appears whenever that pane is inside a Git repository, with how many files have changed and how far the branch is ahead of or behind its upstream. Click it to open Source Control.

When something fails that can be tried again, the bar says so beside the branch, with the reason on hover and a Retry button: Settings weren’t saved, or a shell that did not start, such as Git Bash didn’t start. Other short notices, such as why a dropped file was refused, appear in the same place and can be dismissed.

The waiting item is a count — N waiting — that stays as long as anything is waiting. For a few seconds after a new pane goes quiet, a chip joined to its left names that pane under a draining bar; click the chip to jump straight there, the way Undo close restores. Open the count to see the list, then select a pane to return to it; with two or more waiting, Dismiss all clears them at once. It is hidden when empty unless you enable Settings → Agents → Always show it, even when nothing is waiting, in which case it reads 0 waiting. See When a pane needs your attention for notification controls and what makes a pane qualify.

Ctrl+Shift+N (⌘+Shift+N on macOS) jumps to the newest waiting pane, bringing it back from the shelf or out from behind a maximized pane if it has to. Focus the previous pane takes you back to where you were; it has no default shortcut, so give it one in Settings → Shortcuts or run it from the command palette.

In a narrow window the branch and workspace items drop their names and the Undo chip drops the pane’s; marks and counts stay.

Stashing

A pane can be stashed with Ctrl+Shift+S or the header’s ↓ button: hidden from the grid while its shell keeps running and its scrollback survives. This hides a job, it does not stop one. A stashed browser pane is the same bargain — the page stays loaded, and restoring it returns the same scroll position — and a stashed editor keeps its tabs and any unsaved edits in them.

Stashed panes collect behind a count in the status bar, immediately to the left of Workspace. With pane motion on, a stashed pane flies down into the count, which bumps as it lands, and a restored one rises back out of it into its cell.

Click the stash count — or reach it with Tab and press Enter, or press Ctrl+Shift+O from anywhere — to open the shelf in the window’s bottom-right corner: a list with one row per parked pane. A row says what the pane is, with a mark for its kind and the name its header shows, and where it is: a terminal’s whole folder, a page’s address, the file an editor has open, an SSH pane’s host.

  • Click a row, or press Enter on it, to restore that pane into the first free slot. The list closes so you can watch it land.
  • Close a pane without restoring it with the row’s ×, a middle click on the row, or Delete (Backspace too, while the list has no filter). The row slides out and the list stays open, so you can close several in a row.
  • Restore all and Close all sit at the foot of the list whenever more than one pane is parked, and on the count’s right-click menu (or Shift+F10 with the count focused). Restore asks first only when the panes in the grid plus the ones on the shelf would exceed nine, and close always asks, saying what closing means under your Undo close setting. Both are in the command palette too, as Restore all stashed panes and Close all stashed panes, with no default shortcut.

A parked pane that went quiet while you were elsewhere moves to the top under Waiting on you, with the time it went quiet, and its row glows in the attention color. The rest follow under Stashed, most recently stashed first.

The list takes the keyboard while it is open. ↑ and ↓ move through the rows and the foot and wrap around, Home and End go to either end, and Esc puts the list away and hands the keyboard back to your pane. Nothing you type reaches a shell while the list is open, and any other shortcut puts the list away first and then does its job. Opened from the keyboard, the list starts on its first row. Opened with a click, nothing is selected until you press an arrow or point at a row, and pointing and the arrows move the same single selection.

Past eight parked panes a filter box appears above the rows, and every opening starts on the first row. The filter is one more stop in the loop: ↑ from the first row reaches it, and ↑ again continues from the bottom, so holding an arrow cycles through everything. Start typing on any row to filter by name or place; Enter in the filter moves to the first match, and Enter again restores it.

When the last stashed pane is restored or closed, the stash count disappears. The status bar itself stays in place.

Undoing a close

Closing a terminal removes its pane immediately, but the shell underneath keeps running during the undo window. Undo close in the status bar restores the most recently closed terminal in one click, and names the pane it will bring back; the closed-pane count opens the full list. These controls appear before Stash and Workspace, keeping that pair together at the far right.

A draining bar shows how long each shell will remain available, and each row of the list counts its seconds down. A row’s Restore brings that terminal back and its × closes it now; with two or more closed, Restore all and Close all now act on the whole list. Show recently closed panes opens the list with the keyboard on its first row, from the command palette or a shortcut you give it.

Restoring one re-adopts that shell with its program still going and its recent output replayed, including whatever it printed while it was gone. If no pane has been opened, closed or stashed since, the grid goes back exactly as it was at the close, with the restored pane in its old place; otherwise it takes a free cell like a new pane. With pane motion on, a closed pane fades from its place and a restored one settles into its cell.

Only when its timer runs out is the shell actually killed; opening the list does not extend that deadline. Closing the window or quitting TermHQ ends any shell still counting down, rather than leaving it running where nothing can reach it.

A shell that ends by itself is never parked; there is nothing to restore. Nor is a browser pane: closing one is final, because the undo window exists to hold a shell that is still running and a page has nothing left running to hold.

An editor pane has its own protection instead of an undo window — closing one with unsaved work asks about each file first.

The behavior is configurable in Settings → General:

  • how long the undo window lasts, in seconds (default 5)
  • whether closing with the pane’s × button also offers undo, or only the keyboard shortcut does
  • whether the feature is on at all

Ctrl+Shift+R — Restore last closed terminal — undoes without reaching for the mouse, the same restore as Undo close in the status bar.

Ultra focus

Some terminal programs want chords TermHQ also uses. Ultra focus (Ctrl+Shift+U) hands every keystroke to the terminal, turning off TermHQ’s own shortcuts so a TUI gets them unmodified. See Keyboard shortcuts for exactly what it does and does not take.

Because a mode that swallows the keyboard could trap you, the chord that turns it on always turns it off, and a badge appears in the title bar that can be clicked to leave.

Browser panes

https://termhq.dev/docs/browser-panes/

A real web page as a pane in the grid: the OS browser engine embedded in TermHQ, with the same drag, stash, resize and maximize moves as a terminal.

A pane in TermHQ does not have to be a terminal. Ctrl+Shift+B opens a browser pane — a web page tiled in the grid beside your shells, with the same header, the same drag, stash, resize and maximize moves, and the same place in your saved workspace.

The page is rendered by your operating system’s own browser engine, embedded directly in the window. Nothing is streamed and no input is faked: scrolling, typing, text selection, hover, video and IME are the engine’s, exactly as in the browser you already use.

Opening one

Three ways, all equivalent:

  • The globe in the title bar, just right of the favorites star
  • Ctrl+Shift+B
  • The command palette (Ctrl+Shift+P) — “New browser pane”

Settings → Browser → Browser button on the titlebar removes the globe if you would rather have the space. Turning it off moves it into the menu behind the + button’s caret, as a Browser row after your shells; the chord and the palette keep working either way. (With SSH turned on, that menu ends with Connect via SSH… — see SSH connections.)

Where it lands is Settings → Browser → New panes open. Point it at localhost:3000 and the chord drops you on your dev server; leave it empty and you get a blank pane with the URL bar waiting.

A link in a terminal can open straight into a pane: Ctrl+Shift+click it (⌘+Shift+click on macOS) and it opens in a new browser pane at that address. A plain Ctrl+click (⌘+click) sends it to your system browser instead.

Every browser pane is a native webview with its own renderer process, so opening a tenth one onto the grid asks first — Open anyway, or Don’t warn again. Stashed panes are not counted. Settings → Browser → Warn before the tenth browser pane is the switch.

The URL bar

It reads what you type the way a browser’s does:

You type What happens
https://termhq.dev Opens it
localhost:3000, 127.0.0.1:8080 Opens it over http://
termhq.dev Anything with a dot opens over https://
file:///C:/notes.md Searches for it — see below
rust lifetimes Searches your configured engine

The search engine is Settings → Browser → Search engine — DuckDuckGo (the default), Google, Bing or Brave. Web addresses and localhost ports are never searched; they open directly.

A browser pane may only navigate to http, https and about. Type a scheme it is not allowed to open — file:, vscode: — and it becomes a search rather than an error, because the alternative is a URL bar that silently swallows what you typed and looks broken.

Enter navigates. Clicking into the bar selects the current address so typing replaces it. Esc discards a half-typed address, restores the page’s current URL, and hands the keyboard back to the page. A blank pane opens with the bar already focused. While you are typing in it, the chords that act on panes stand down, so closing or stashing cannot fire from the address bar; only the launchers — the command palette, Settings, the workspace picker and the like — dictation, and the shortcuts that move focus to a neighboring pane still answer. Those last ones work from the pane’s find bar too, so the keyboard can always leave a browser pane.

Back, forward and reload sit to the left of the bar. The back and forward buttons dim when there is nowhere to go, like a real browser’s, and while a page loads, Reload turns into Stop. Beside the address, a lock means the page arrived over HTTPS and a warning sign means plain HTTP — except for this machine’s own addresses (localhost, 127.x.x.x, [::1]), where a dev server without encryption is normal and a warning would be noise.

The ⋯ button near Close is always there, at every width. It holds Rename, Web devtools — the full inspector for that page, in its own window — and Copy address.

The pane’s title follows the page’s. Rename it — right-click the header, press F2 on it, choose Rename from the ⋯ menu, or run “Rename the focused pane” from the command palette — and your name sticks instead, the same as a terminal. Clear the name to go back to the page’s title. Double-clicking the header maximizes the pane.

The focused pane keeps its speaker, Stash and Maximize in view. Other panes fold them away until the pointer is over them, and the page title glides into the space they were holding, un-truncating as far as the address bar can spare. The one thing that never folds is a muted page’s speaker — it pins itself beside Close and stays visible, because silence with nothing on screen to explain it reads as a fault rather than a setting.

On a narrow pane, the page title drops away. On an even tighter pane, back, forward, reload, the speaker, Stash and Maximize fold into the ⋯ menu as well, so the URL bar, ⋯ and Close remain reachable at every width. A thin sweep along the bottom of the header shows when a page is loading. The first real page also gets a simple pulsing loading surface until it is ready, instead of an unexplained empty pane.

When a page won’t load

A page that cannot be reached does not leave the pane blank. A Page unavailable card keeps the address you asked for, says why, and offers Retry, Copy address, and Open externally, which hands the address to your system browser. A load that never finishes gets the same card after 30 seconds — and if the page does arrive later, it still shows.

A server’s own error page, such as a 404, is still a page: it stays visible like any other. And if the browser surface itself cannot be created, the pane says why and offers Retry.

Sound

Pages play audio like any browser. Settings → Browser → Sound in new panes turns that off for new panes, and each pane’s header has a speaker that mutes or unmutes that one page live. The speaker stays visible while a pane is muted, so silence is never a mystery.

Muting works on Windows and macOS. On macOS it goes through WebKit, and on a version of macOS whose WebKit cannot control page audio, pressing the speaker shows an error saying so rather than pretending. A pane’s mute is a choice for that session: the workspace does not remember it.

It is a pane like any other

Everything the grid does, a browser pane does:

  • Drag its header to move, swap or grow it, exactly as with a terminal
  • Drag the gutter beside it to give the page the width it wants — the reason resizing exists at all, since a web page has a natural width and a terminal does not
  • Stash it — the page stays loaded and keeps playing; restoring brings back the same scroll position
  • Maximize it — its header button, or a double-click on the header — and restore the grid the same way; arrange it from the keyboard, move focus to it

Its header wears a globe where a terminal’s wears a prompt, so the kind of pane reads at a glance, and it renames the way a terminal’s does: F2 or a right-click on the header.

Panes glide into place when you swap, move or resize them, with a browser pane on screen too: the page rides along as a still picture, keeping its size while the pane reshapes around it, and comes back live where it lands. While you resize the window, a border between panes or the sidebar, the page holds still in the same way until you stop, so it never runs ahead of its pane. A new browser pane settles into its cell, a closed one fades from its place, and stashing and restoring fly it into and out of the shelf. Settings → Appearance → Animate panes turns all of that off, and so does reduced motion in your system settings — see Pane motion.

Closing or stashing the browser pane you are using hands focus to the pane you used before it, so the keyboard always has somewhere to go. And a file dropped on a browser pane is turned away with a note rather than opened: a browser pane opens web addresses, not files.

A link that opens a new tab — target="_blank", or a window.open from the page — opens another browser pane rather than an operating-system window. Cloning a browser pane opens a sibling at the same URL. Neither takes the home page: only the panes you open yourself do.

One move a terminal has that a browser pane does not: closing it is final. The undo window exists because a closed terminal’s shell is parked and still running in the background, and a page has nothing parked to come back to.

Workspaces remember pages

A saved workspace stores each browser pane’s address and its place in the grid, so reopening it puts the pages back where they were. Logins and cookies live in the engine’s own profile, so “signed into the dashboard” survives a restart.

Browser panes are part of the window, not of the shell host, so a full quit closes their pages and reopening navigates back to them. Shells are the thing that keeps running across a quit — see Persistent sessions.

Keys over a page

On Windows and macOS, TermHQ’s own chords keep working while a page has the keyboard: pane focus, arrange mode, stash, close, maximize and the pickers are all intercepted before the page sees them, exactly as if a terminal were focused. After a chord runs, the keyboard lands where the result needs it — back in the page, or in the app for arrange mode’s arrows and a picker’s digits. The dictation chord is caught too, and over a page it types what you say into the page’s focused text field — see Dictation.

A short list stays deliberately with the page. Copy, because the page’s version is the one you want. The agent picker, because it would only type into a terminal that is not there. And on Windows, Ctrl+F opens the engine’s own find bar and Ctrl+= / - / 0 are the engine’s page zoom.

On macOS, ⌘+F opens TermHQ’s own find bar on the pane, which drives the page’s search: Enter and Shift+Enter step through matches, it says when there are none, and Esc hands the keyboard back to the page. ⌘+= / - / 0 zoom the page, and the usual browser keys work while the page has the keyboard — ⌘+L for the address bar, ⌘+[ and ⌘+] for back and forward, ⌘+R to reload — unless you have bound one of those chords to something else.

Ultra focus (Ctrl+Shift+U) hands the page every key except its own toggle.

The page has no keys to the app

A browser pane loads whatever you point it at, so it is given no authority at all. Browser surfaces are in none of the application’s capabilities, and navigation is limited to http, https and about — never a local file, a custom protocol, or TermHQ’s own interface.

The fence doing most of the work is the third: remote origins are refused any channel into TermHQ wholesale, a layer below the point where a page could ask. Development builds report what a page can see after every load, as a drift detector — the bridge object is visible to the page; what it cannot do is use it.

What v1 does not do yet

Stated plainly rather than discovered later:

  • Windows and macOS have both had a full pass, including the frozen frame described below and the pane’s rounded bottom corners. Linux support is pending.
  • Anything that must cover the grid covers the page. A native page cannot be painted over by the interface, so when a modal, menu, drag preview, or similar overlay needs the space, the pane shows a frozen frame of the page for as long as the overlay is up, then goes live again. Video keeps playing underneath; it simply looks paused while covered. This includes opening the waiting-pane list, closed-pane list or stash shelf. Their status-bar buttons sit below the grid and do not freeze the page on their own. The frame is a courtesy rather than a guarantee — a pane nobody can see does not pay to capture one, and neither does a second overlay arriving right behind the last, where the previous correctly sized frame or the pane’s background is shown.
  • Downloads use the engine’s own default handling.
  • One browser profile, shared by every workspace. Per-workspace profiles are a real feature with real questions, and are deferred rather than faked.

SSH connections

https://termhq.dev/docs/ssh/

A shell on another machine as a pane in the grid, through the OpenSSH client you already have: typed targets, saved profiles, your ssh config's aliases, and a way back when a connection drops.

An SSH pane tiles, stashes, maximizes and clones like any terminal. It uses the keys, agent and ssh config you already have, installs nothing on the machine you connect to, and needs no account anywhere.

SSH is off until you turn it on.

Turning it on

Open Settings → SSH and switch on SSH connections. Then:

  • Connect via SSH… appears at the bottom of the + button’s shell list (its caret opens the list).
  • The command palette’s Connect via SSH opens the picker.
  • Settings → SSH shows its other two options: which client to use, and the keep-alive.

While it is off, there is no SSH entry under the + button, and Settings → SSH shows only the switch. The palette still lists Connect via SSH, so you can find it, but refuses it with SSH is off in Settings → SSH.

The switch only decides where new connections start. SSH panes you already have — open, stashed, or restored from your last session — keep working either way, Reconnect and Clone included.

What you need

Only the OpenSSH client, which your system most likely has already. TermHQ looks in these places, and Automatic uses the first client it finds:

Platform Where TermHQ looks, in order
Windows Windows OpenSSH (C:\Windows\System32\OpenSSH), then Git for Windows’ client (C:\Program Files\Git\usr\bin), then any ssh.exe on your PATH
macOS /usr/bin/ssh, then Homebrew’s in /opt/homebrew/bin, then /usr/local/bin/ssh, then any ssh on your PATH

Settings → SSH → OpenSSH client lists every client found, each with its version. Pick one to use it instead of the automatic choice, or choose A path… and give the full path of any other ssh. Below the list, Settings says which client is in use and which config file it reads.

Whichever client you use, its own agent, keys and configuration are the ones in play. On Windows TermHQ never mixes the two clients, so if your keys live in the Windows ssh-agent service, use Windows OpenSSH.

If no client is found, Settings and the picker say so. Windows includes the OpenSSH Client as an optional feature of Windows itself, and Git for Windows carries its own; every Mac has /usr/bin/ssh.

On the machine you connect to, you need nothing but the SSH server you already reach.

Connecting

Three ways to open the SSH picker:

  • Connect via SSH…, the last entry in the + button’s shell list
  • The command palette (Ctrl+Shift+P, or ⌘+Shift+P on macOS) — “Connect via SSH”
  • A shortcut of your own. The action ships without one, because every free chord was already taken; give it one under Settings → Shortcuts.

With SSH on, the palette also lists each saved profile and your most recent targets as Connect to … rows, which connect straight away.

The picker is one box over one list. The list has up to three sections — Recent, Profiles and From your ssh config — and typing filters all three at once. Click a row to connect, or use the keyboard:

Key What it does
↑ ↓ Move through the list
Enter Connect to the highlighted row — or, with none highlighted, to what you typed
F2 Edit the highlighted profile
Delete Delete the highlighted profile (it asks first), or forget the highlighted recent target
Esc Close the picker

As you type, the line under the box says what Enter will connect to, or why it can’t. The footer names the client in use, its version and the config file it read. Once the connection starts, the picker closes and the new pane joins the grid.

What you can type

You type It means
build.example.com A host
alex@build.example.com A user and a host
build.example.com:2222 A host and a port
[2001:db8::10]:2222 An IPv6 address, in brackets when it has a port
ssh://alex@build.example.com:2222/ The same things, written as an address
staging An alias from your ssh config, or any name the client can resolve

The user can be a directory account: alex@corp.example@build.example.com and CORP\alex@build.example.com both work.

The picker refuses, with the reason under the box: a space (a target is just the host, not a command), a leading -, a path, or a port outside 1–65535. Nothing you type or paste is ever run as a command.

Hosts from your ssh config

From your ssh config lists the hosts named in ~/.ssh/config (%USERPROFILE%\.ssh\config on Windows). TermHQ reads the file the way the client does and never writes to it:

  • Only concrete Host entries are listed. Wildcard patterns and Match blocks name no single host, so they are left out.
  • Include lines are followed, and the hosts in included files are listed too.
  • Nothing in the file is run. A ProxyCommand or Match exec runs only when you connect, and the client runs it, as it would from any terminal.

Saved profiles

A profile keeps a connection’s settings under a name. To make one, type a target and choose Save…, which opens the form with what you typed already filled in. With the box empty, New profile… starts one from scratch. To change a profile, use the pencil on its row, or highlight it and press F2.

Field What it sets
Name What the picker shows, and what the pane is called
Host A host name, an address, or an alias from your ssh config
User The login user; empty means the client’s default
Port Empty means the client’s default
Key file A private key for this host (the client’s -i)
Jump host A host to connect through (-J): bastion, alex@bastion:2222, or several hops separated by commas
Config file A config file to use instead of ~/.ssh/config (-F)
Known hosts A known-hosts file to use instead of ~/.ssh/known_hosts

The last two sit under More options. Only the fields you fill in reach the client; everything else comes from your ssh config and the client’s own defaults.

File fields have a folder button that opens your system’s file dialog. Type a full path, or one starting with ~. A path that contains % or ${…} is refused: OpenSSH reads those as placeholders of its own, so it would open a different file from the one you named.

A problem shows under the field that has it, and a save TermHQ refuses keeps the form and everything you typed. Change a form and then press Esc, choose Cancel or click outside it, and it asks Discard what you typed? first.

Deleting a profile asks first. A recent target has an × to forget it. The picker remembers the last twelve targets you typed or picked from your ssh config; a connection made through a profile is remembered by the profile’s own row instead.

Where profiles are kept

Profiles live in ssh-profiles.json, beside config.json in TermHQ’s configuration folder. The file holds settings, never secrets: a key file’s path may be saved, but never a password, a passphrase or the key itself.

If the file can’t be read — a hand edit gone wrong, or a file from a newer TermHQ — the picker says so and leaves the file exactly as it is. Typed targets still connect.

Editing or deleting a profile changes only the connections you make afterward. A pane that is already open keeps the settings it connected with, and Reconnect uses them.

Passwords, keys and host keys

Every prompt in an SSH pane is the client’s own. It writes the prompt into the pane, and you answer it there: a password, a key’s passphrase, a one-time code or other MFA prompt, the question about a host you have never connected to (with its fingerprint), and the client’s refusal when a host’s key has changed.

TermHQ reads none of these prompts and types no answers. It stores no password or passphrase, and it never adds or removes an entry in your known_hosts. When you accept a new host’s key, the client records it, as it always has.

What a remote pane shows

The header keeps the shape it has on a local pane:

  • The name is where the pane goes — the target you typed, the alias you picked, or the profile’s name. Rename it like any pane.
  • The badge sits where a local pane shows its shell’s name. It carries the remote mark and the connection’s state, and after a rename it names the connection too. Hover it to see the exact command the pane ran.
  • The path is the remote shell’s directory, once the shell reports it. Hover it to see which host it belongs to.
The badge says It means
connecting… The client has started, and nothing has arrived yet
nothing but the mark The client is running, and output has arrived
shell ready The remote shell has reported its directory
ended The connection has ended
not connected Restored from your last session, and not connected since

TermHQ shows only what the client can tell it. OpenSSH sends no signal when a login succeeds, so none is claimed: shell ready waits for evidence from the far side.

If nothing arrives within two seconds, the pane says so — Connecting to build.example.com… 5 s, counting — with a Cancel button that closes it.

On the stash shelf, a stashed SSH pane’s row names the host, followed by the remote folder when the shell reports one.

When a connection ends

When ssh ends — the remote shell exited, the network dropped, a login failed — the pane stays, with all its output, and a card appears below the output. It says:

  • How it ended. A shell that exits normally reads The shell on … ended. Code 255 is the one OpenSSH uses for every connection and authentication failure alike, so the card says just that and points you to the output above it, where the client names the real reason.
  • The command that ran, the first two lines of it, with the rest on hover.

And it offers three buttons:

  • Reconnect — a new connection with the pane’s own saved settings, in the same place.
  • Open local terminal here — your default shell, in this pane’s place.
  • Close.

Enter in the pane also reconnects. It is the key people press after “Connection closed”, so it does the useful thing rather than closing the pane. If the pane doesn’t have the keyboard, click beside the card first.

While an attempt runs, Reconnect reads Connecting… and the card’s buttons wait. An attempt that cannot even start — the client has moved, a key file is gone — says why on the card and gives you the buttons back. A rename survives Reconnect, and a maximized pane stays maximized.

A remote pane never quietly turns into a local shell. That happens only when you choose Open local terminal here.

Keeping idle connections alive

Routers and firewalls often drop a quiet connection after a few minutes without telling either end, and a connection that has died is otherwise noticed only at your next keystroke. So every connection sends a keep-alive through the encrypted channel, every 30 seconds by default.

Settings → SSH → Keep idle connections alive sets the interval, from 0 to 120 seconds in steps of 15. It is the one option TermHQ adds to the command on its own, as -o ServerAliveInterval=30. Because an option on the command line outranks your ssh config, it replaces any ServerAliveInterval you set there. At 0 — shown as off — nothing is added, and your config decides.

Quitting and coming back

The ssh process behind a remote pane runs in TermHQ’s background host, like every shell — see Persistent sessions. What you get back depends on whether that process is still running.

It is still running. Closing the window or quitting TermHQ leaves the connection open. Relaunch, and the pane picks it up with its recent output. The badge shows shell ready again once the remote shell next reports its directory.

It is gone. After a reboot, after an update restarts the background host, or when the connection ended while TermHQ was closed, the pane comes back in its place saying Not connected to … and “Nothing connects until you ask.” Press Reconnect or Enter when you want it. A workspace full of SSH panes opens quietly, rather than with a login prompt in every pane.

What no local process can keep alive is the connection itself. Don’t count on a remote session surviving a lost network, sleep, a reboot or an update: when the connection ends, the shell on the far side ends with it, and so does whatever was running in it.

Stashing and closing

  • Stashing keeps the connection: the pane is hidden, not stopped.
  • Undo close works as it does for any terminal. The connection stays open through the undo window and ends when the window runs out. If it drops during the window, Undo brings the pane back ended, with its card.
  • A pane with no connection behind it — ended, or restored as not connected — closes outright, because there is nothing for Undo to bring back.

What stays local

A remote pane’s directory is on another machine, so it is kept away from everything that works with local folders:

  • Files, Source Control, favorites and Worktrees never see the remote path.
  • The header has no Open in IDE and no Star; both act on a local folder.
  • The agent launcher is not offered. Its list is what this machine found on its PATH, which says nothing about the far host: the header has no launcher button, the palette’s Run an agent by number says why it can’t run, and its shortcut does nothing.
  • Files dropped on the pane are refused — This machine’s paths mean nothing on … — rather than typed in as paths.
  • Clone opens a second connection to the same host, with the same settings. It starts where a new login starts, not in the directory you are in.

How the command is built

  • TermHQ builds the ssh command from checked fields — a host, a user, a port, the files and the jump host — never from text. Nothing you type or paste can become an option or a command.
  • Settings apply in this order: what you set on a profile or typed into the picker, then your ssh config, then the client’s own defaults. The keep-alive is the one thing TermHQ adds.
  • The exact command is on the badge’s tooltip and on the card when a connection ends, so you can always read what ran.

Limits

  • Linux: TermHQ is not released there yet.
  • Not built yet: a starting directory, tunnels (port forwarding), remote files, and Git and language services on the remote machine.
  • Code 255 can’t be read further. A failed login and a lost network both end with it, so the card can’t tell them apart — the output above it can.
  • The shell ready badge needs the remote shell’s help. It appears only when the shell reports its directory, which not every shell does out of the box. Without it the badge stays at the mark, and the pane works the same.
  • Windows OpenSSH refuses a config or key file that other accounts can read. The client says so in the pane; limit the file to your own account.
  • An ssh you type in a local pane is an ordinary program running in that shell, not an SSH pane: no badge, no card, no Reconnect.

The editor

https://termhq.dev/docs/editor/

Editor panes: files as tabs, saving that cannot lose work, reading markdown, and the keys a VS Code hand already knows.

A pane can hold a file. Ctrl+Shift+E opens an empty editor pane, and it behaves like every other pane — drag it, stash it, maximize it, resize it, zoom its text, and find it where you left it when the workspace comes back.

Its header works the way a terminal’s does. A page mark stands where a terminal shows its prompt; double-click the header to maximize the pane, and right-click it or press F2 on it to rename the pane. The focused pane keeps its header tools — Stash, Maximize, and the reading view for a markdown file — in view, while other panes show theirs when the pointer is over them. On a narrow pane they move into a ⋯ menu, so Close is always in reach.

TermHQ is still a terminal, not an IDE. The editor exists for the edit you make while something else is running: the config line an agent asked about, the README you are reading, the fix that is faster to type than to explain.

Opening a file

The Files panel is the daily door. Double-click a file and it opens in the editor pane you last used — or opens a new one if you have none. Right-click gives you the choice: Open in editor, Open in new editor pane, or the external routes — the system default, your IDE, and the editors grouped under Open with, terminal editors included. The same menu can reveal the file in File Explorer or Finder with the file selected (on Linux it opens the containing folder), Copy path, Copy relative path — the path from the panel’s root — and File history, which opens the file’s history in the Git panel.

You can also drag a file onto an editor pane — out of the Files tree, or from your desktop — and it opens there as a tab. An empty cell in the grid offers New terminal and Open file…; a file picked there opens in a new editor pane in that cell.

Opening a file that is already open just switches to its tab. Opening it in a different pane gives you a second live view of the same file — type in one and the other keeps up, because both are looking at the same file rather than at two copies of it. Duplicating an editor pane does the same thing for every tab at once: a second view of the same files, not a copy of them.

If the appropriate editor is stashed, opening a file brings it back into the grid. An editor that already holds that file is preferred, so opening it again does not leave duplicate editors on the shelf.

An empty editor pane has an Open file… button that goes through the system picker, for when the Files panel is closed or showing the Git tab.

Files are tabs

Each editor pane has its own tab strip. Scroll it with the wheel, drag tabs to reorder them, middle-click to close one. The strip keeps the active tab in view, and fades at an edge where more tabs continue. Every tab carries the same file-type icon the Files panel uses, so the tree and the strip always show the same picture. Two tabs with the same name each show their parent folder, so index.ts from src and index.ts from lib can be told apart.

The selected tab is exposed to accessibility tools. When the tab strip has keyboard focus, the left/right arrows switch files, and Home or End selects the first or last tab. The shortcuts below still work from inside the editor.

The active tab renames the pane and sets its working directory, which means the Files and Git tabs follow what you are editing exactly as they follow a shell.

Action Shortcut
Next / previous tab Ctrl+Tab / Ctrl+Shift+Tab
Next / previous tab, again Ctrl+PageDown / Ctrl+PageUp
Jump to a tab Ctrl+1 … Ctrl+8
Jump to the last tab Ctrl+9
Reopen the tab you just closed Ctrl+Shift+T
Close the tab Ctrl+W
Save Ctrl+S
Save every unsaved file in the window Ctrl+K then S

Tab cycling wraps, so with two tabs open one chord flips between them. Ctrl+9 is the last tab however many there are, the way it works in a browser. Ctrl+W on the last remaining tab closes the pane.

On macOS, ⌘ replaces Ctrl in all of these — with one exception: Ctrl+Tab stays Ctrl on every platform, because that is the cycle-through-tabs key everywhere.

Those chords are bound inside the pane, which is why they cost your shell nothing: Ctrl+S still freezes a terminal’s output and Ctrl+W still deletes a word, everywhere except an editor.

Going back

Alt+← and Alt+→ walk back and forward through the places you have been, so a go-to-definition that landed somewhere unhelpful is one key from being undone. On macOS these are Ctrl+- and Ctrl+Shift+-, because Alt+arrow is word movement there.

The history belongs to the pane, not the window. With three editors open, going back in one never scrolls another you were not looking at.

Editing

The editing surface is Monaco — the engine behind VS Code — so multi-cursor, column selection, find and replace, bracket matching and the rest of the usual moves are already there. It uses your terminal font, and Ctrl+= / - / 0 zoom one pane’s text exactly as they do a terminal’s, as does Ctrl+wheel (⌘+wheel on macOS), each showing the new size low in the pane — on top of a base size that follows your terminal font until you turn Settings → Editor → Font size follows the terminal off and set the editor’s own. That panel also carries soft word wrap and the minimap, both off by default, and a reference list of Monaco’s own keys.

The editor wears the active theme, including its surface, cursor, selections, widgets, diffs, and syntax. Built-in and hand-made themes draw syntax from the terminal palette, so an editor and terminal beside each other belong to the same workspace. Themes imported from Open VSX keep their own editor colors and syntax rules. See Theming.

Ctrl+F opens Monaco’s find widget while an editor is focused, rather than the terminal’s scrollback search. That is one of a small set of chords the editor keeps for itself — see Keyboard shortcuts.

For diagnostics, hover, completion, go-to-definition and formatting, see Language servers. Those come from tools you install; TermHQ ships none.

Saving cannot lose your work

Every save writes to a temporary file first and then swaps it into place, so a save that fails partway — a full disk, a permission, a read-only file — leaves the original exactly as it was. You get a card naming which of those happened, a Retry, and your edits still sitting in the buffer. A save that lands shows Saved on the pane for a moment.

Saves are also guarded against overwriting someone else: if the file changed on disk since you opened it, TermHQ notices before writing rather than after.

When the file changes underneath you

Agents write files. So do formatters, git checkout, and the pane next door.

  • With no unsaved edits, the tab quietly reloads within a second or two, keeping your cursor and your undo history.
  • With unsaved edits, a card appears offering three honest options: Compare (a side-by-side diff of disk against what you typed), Reload from disk (throw your edits away), or Keep my changes (your next save wins, and you knew it would).

A file deleted while you have it open is flagged rather than closed. The card waits 800 ms first — a program that saves by writing a new file and renaming it over the old one looks like a delete for an instant — and then offers Dismiss, Close tab, or Save to restore it, which writes your buffer back to disk.

These cards arrive on the file’s schedule, not yours, so they are careful with the keyboard. A card takes it only in the pane you are using, and then it focuses the card itself rather than one of its buttons, so an Enter meant for another pane can never answer it. Esc returns the keyboard to your text.

Renaming a file or folder in the Files panel carries open tabs along to the new name. A tab with unsaved edits stays where it was, because its buffer holds the only copy of that work; its card then reports the file as deleted, and saving writes it back under the old name.

Closing without losing work

Three guards, at three scales:

  1. Closing a tab with unsaved edits asks Save / Don’t save / Cancel.
  2. Closing a pane asks once about every unsaved file about to lose its last view — Save all and close, Discard and close, or Cancel. A file still open in another pane needs no question — it is not going anywhere.
  3. Closing the window with unsaved work anywhere stops and offers Save all & quit, Quit without saving, or Cancel.

If the app dies instead

Those guards cover the endings you choose. Unsaved text is also mirrored to disk about a second and a half after you stop typing, so the endings you do not choose — a crash, an end-task, a power cut — do not take your work either.

When the file reopens, the tab comes back still unsaved, dirty dot and all. There is no “restore your work?” prompt, because the answer to that question is always yes; one undo reaches the version on disk if the restore was unwanted. If the file also changed while the app was gone, you get the ordinary conflict card instead.

Records clear the moment they stop being true — on save, on reload, on undoing back to the saved text, on closing the tab. Settings → Editor → Recover unsaved changes after a crash turns the whole thing off and deletes anything it had mirrored. Text over 4 MB is not mirrored.

An orderly quit deliberately does not preserve unsaved buffers. The quit guard above exists so that is always a decision you made rather than a surprise.

Reading markdown

A .md tab has three views, and each chord toggles:

View Chord What you get
Source — The file as text
Split Ctrl+K then V Source on the left, rendered on the right
Full Ctrl+Shift+V The rendered page, filling the tab

On macOS those are ⌘+Shift+V and ⌘+K then V. The header button walks all three if you would rather not learn the chords, and the split divider drags wherever you want it — double-click to even it up.

Saving and closing work the same in every view, so Ctrl+S and Ctrl+W still do their jobs while you are reading. Find is the one that moves you: the rendered page has no search of its own, so Ctrl+F flips the tab back to source and opens the find widget there rather than appearing to do nothing.

The two halves scroll together, anchored on the source line each rendered block came from rather than on a percentage of the two heights, so a long table, a code fence or an image cannot drift them apart.

The view belongs to the tab, so a README can sit rendered beside code that stays source. And it renders the buffer, not the file: your unsaved edits show up, and an agent rewriting the file redraws it.

Headings, tables, quotes and code blocks are themed from the same colors as the rest of the app, so an imported theme carries the preview with it. Code fences are syntax highlighted, by the same colorizer the editor uses on the file itself — so a fence is painted in the theme you are already wearing, and switching themes recolors it. A fence tagged with a language name the editor does not know simply renders plain. Relative links open as another tab in the same pane; web links open a browser pane.

Two current limits: relative images do not load, and [[wikilinks]] render as plain text.

A document is never trusted. Real READMEs contain HTML, so the preview keeps what merely presents — centered blocks, badge images, collapsible sections, and the checkboxes of a - [x] task list — and drops anything that could run, embed, restyle or navigate somewhere of its own accord. Link destinations are limited to safe ones.

Images, binaries, and very large files

Images (PNG, JPEG, GIF, WebP, SVG and friends) open in an image view inside the same tab strip. Binary files, anything that is not UTF-8 text, and files over 20 MB get a plain notice rather than a mangled buffer. SVG opens as a picture — to edit one as text, use the Files panel’s Open with routes.

The Files panel while you edit

With an editor focused on a file inside a git repository, the Files panel roots itself at the repository rather than at the file’s own folder, expands the tree down to that file, and keeps its row highlighted — the shape VS Code’s explorer uses. A file outside any repository falls back to the folder view, and terminals are never affected either way.

Wandering the tree yourself is respected: nothing yanks the view back until the file you are editing actually changes. Settings → Editor → Files panel shows the repo while editing turns it off.

Inside a repository, the tree also shows where things stand with Git: a changed file’s name is tinted and carries its status letter, a folder holding changes is marked with a dot, and names Git ignores are slightly gray — hover one and it says “Ignored by Git”. Outside a repository, nothing in the tree looks different.

The tree draws a hairline down each level of indentation so a deeply nested file still reads as belonging to its folder. Most stay invisible until your pointer is in the panel; the deepest open folder on each branch stays lit, so “how far down am I on this side” is answerable at a glance.

Saving a file refreshes its row in the tree, so a size shown there is the size on disk rather than the size from the last listing.

What it does not do yet

  • No creating, renaming or deleting files from the editor — the Files panel’s right-click menu is where that lives.
  • Cursor position survives tab switches and stashing, but not an app restart.
  • UTF-8 only.
  • A read-only file refuses to save and says why, rather than offering to change the file’s permissions for you.

Language servers

https://termhq.dev/docs/language-servers/

Diagnostics, hover, completion, go-to-definition and formatting in editor panes — from language servers you install, never bundled.

An editor pane on its own gives you syntax highlighting and the usual editing moves. Point a language server at it and it also gives you:

  • Diagnostics — errors and warnings as live squiggles
  • Hover — types and documentation under the pointer
  • Completion — suggestions that know your project, not just words in the file
  • Go to definition — cross-file, landing the cursor on the target
  • Parameter hints — the signature of the call you are inside, with the argument you are on underlined
  • Occurrence highlights — every other place the symbol under your cursor appears, reading told apart from writing
  • Formatting — see below

TermHQ ships no language servers

Not as a limitation — as the design. A bundled server is one you cannot upgrade, one that disagrees with your project’s toolchain, and one that ships to everyone who does not write that language. TermHQ launches the servers you install, on your machine, at your version.

Nothing here is required. With no servers installed, editor panes work exactly as described on the editor page.

What is set up out of the box

Five entries ship as configuration, ready for the day you install the binary they name:

Language Server Install it with
TypeScript / JavaScript typescript-language-server npm i -g typescript-language-server typescript
Rust rust-analyzer rustup component add rust-analyzer
Go gopls go install golang.org/x/tools/gopls@latest
Python pyright-langserver npm i -g pyright
C / C++ clangd Your platform’s LLVM package

Install one and it starts working the next time you open a file of that language. Install none and nothing breaks.

Adding your own

Open Settings → Editor → Language server setup, then choose Add a server; the new entry goes at the end of the list. (The setup section is hidden while Language intelligence is off.) TermHQ accepts servers that speak the Language Server Protocol over standard input and output. Each entry has:

  • Name — the field at the top of the entry, which labels it in the list
  • Command — the program name on your PATH, or its full path
  • Arguments — space-separated options passed to that program, such as --stdio. Quoted arguments containing spaces are not supported by this field.
  • Languages — comma-separated language IDs for the file types it should handle, such as typescript, javascript
  • Root markers — comma-separated filenames that mark the top of a project, such as tsconfig.json, package.json
  • Enabled — a switch, so you can park one without deleting it

In Arguments, Languages and Root markers, spaces and commas stay in place while you type. Press Enter, press Tab to move to the next field, or click elsewhere to apply that field’s value. There is no separate Save button.

To delete an entry, press its ×; it turns into Remove?, and only a second click removes the entry.

Restore default servers replaces the entire list with the five above, exactly as a fresh install has them. It does not ask first, and any server you added yourself is deleted along with your changes to the five.

How servers start and stop

You do not start them. A server launches when you open a file it handles, and one runs per project — the project being whatever folder the nearest root marker sits in, walking upward from your file. A monorepo with three Cargo.toml files gets three, each seeing only its own crate.

A server stops about half a minute after the last file using it closes, restarts itself if it crashes (at most twice in five minutes, so a server that cannot start does not spin), and shuts down with the window.

When a server is not working

Every entry under Settings → Editor → Language server setup carries a status chip that tells you the truth rather than a green light:

Status What it means
running Working, serving one project
running · 2 roots Working, serving two projects
starting… Launched, still coming up
checking… Still looking for the command on your PATH
its path, such as /usr/local/bin/gopls Installed; it starts when you open a file it handles
not installed The command is not on your PATH — install it
would not start It is there, but it failed. Hover for its own last words
restarting… Recovering from a crash
disabled Its Enabled switch is off, so it never launches

The dot beside each entry’s name says the same at a glance: lit while the server runs, hollow when it is missing, failing or switched off.

Hover any status for the full story, including whatever the server itself said on the way down — “not found on PATH”, “initialize: no answer after 30s”, or the exit code that killed it. Each entry also keeps the server’s own log under Logs, which is the first thing worth reading when something is wrong.

Restart shows its work: a spinner while a relaunch is genuinely in flight, and a plain answer when there is nothing to relaunch (“cleared — no open file uses this server yet”) rather than a button that looks broken.

One deliberate detail: a missing binary keeps saying not installed even after you press Restart, because the fix is to install it, not to press the button again.

Formatting

Shift+Alt+F formats the document, and Ctrl+K then Ctrl+F formats just the selection. Settings → Editor → Format on save (off by default) does it on every save.

TermHQ never reformats anything itself. The request goes to your language server, so it is rustfmt behind rust-analyzer and gofmt behind gopls, already obeying your project’s own configuration. There is no formatter of ours in the middle to disagree with your repo.

Using a different formatter

The first server in the list that offers formatting owns it. So to format with Prettier, Black, shfmt or Ruff, add a formatting-only server — efm-langserver, diagnostic-languageserver, or ruff server — and put it above the language’s main server. That one formats; the main server keeps diagnostics, hover and completion.

Settings cannot reorder the list, and Add a server puts a new entry at the end. To move it up, close TermHQ and edit config.json: servers are listed in the languageServers array, in order, and the formatter’s entry has to come before the main server’s.

Format on save never waits more than two seconds for a formatter, and never applies edits computed against a version of the document you have already typed past.

When a server wants to change your files

Some servers offer refactors that touch more than the file you are in — a rename across a project, an import added somewhere else.

When that happens, the changes land in buffers, not on disk. Files already open are edited in place; closed ones open as tabs. Everything arrives unsaved and undoable, and nothing is written until you save it. One Ctrl+Z takes back a server’s whole edit for a file.

The edit is all-or-nothing. If anything about it does not fit — a file that moved on while it was being computed, overlapping changes, a file that will not open — the whole thing is refused and the server is told why, rather than half a refactor being applied to your project.

File operations — creating, renaming or deleting files as part of a refactor — are not supported yet, and a refactor that needs one is refused rather than partly done.

Turning it off

Settings → Editor → Language intelligence is the master switch. Off, no server ever launches, editor panes behave exactly as they do with nothing installed, and Language server setup is hidden until you turn it back on.

Individual entries have their own Enabled switch, which is the lighter version of the same idea.

Note that occurrence highlighting keeps working with the whole layer off — it falls back to matching words rather than understanding symbols, which is worth more than nothing while a server is missing, disabled, or still starting.

Workspaces

https://termhq.dev/docs/workspaces/

Group terminals by what you are working on, name them, resume them, and open several at once.

A workspace is a window’s worth of panes: their layout, the directories their terminals are in, the pages any browser panes are on, and optionally a name. Open a second window and you get a second workspace, not a copy of the first. On macOS every workspace window belongs to the one TermHQ application — one Dock icon, all of them in the Window menu — while each keeps its own terminals, editors and language servers.

Anything you tune by hand is remembered with it, including proportions you set by dragging a gutter and whether it uses Grid or Columns.

Settings, on the other hand, belong to the whole app. Change the theme, the background, your favorites, an agent or a shortcut in one window and every open window follows at once. The sidebar and the Grid or Columns choice are the exception: they stay with the window you change them in, and are saved as the starting point for the next new window.

When you reopen a workspace whose terminals are still running, the pane you last selected is selected again, provided it is still available and visible. Selection is saved when you switch panes, even if nothing else changes. After a reboot or update the terminals are new processes, but the selection follows them to their new shells. It falls back to another visible pane only when the pane you had selected is gone or stashed.

The picker

Click the workspace name and window icon at the far right of the bottom status bar to open the picker. Stash sits immediately to its left when you have stashed panes; temporary recovery controls do not split the two.

Ctrl+Shift+W also opens the picker (⌘+Shift+W on macOS). Pressing it again closes it. You can also choose Workspaces from the command palette.

Each row shows the workspace’s name, a badge when it is open in a window (this window for the one you are in) or running in the background, and a line such as 3 panes · created 2d ago · last used 5m ago. The name is the title you gave it, or else the folders its panes are in, or else its slot, such as Workspace 4; a titled workspace shows its title alone. Workspaces are listed most recently used first. Two that share a name show their slot beside it — Workspace 1, Workspace 3 — the one thing about them guaranteed to differ.

Past eight workspaces, a filter box appears above the list. It matches names and folders, and Esc clears it before it closes anything.

The keyboard starts on your most recently used other workspace, so the picker’s shortcut and then Enter switches to it — the way back to where you just were. Choosing the workspace this window already shows simply closes the picker. Use the up/down arrow keys to focus another row, then Enter to open it. Tab moves among controls such as New workspace and Rename; Enter activates whichever control has keyboard focus. Esc closes the picker. Moving the mouse takes over the highlight, and moving the pointer off the list clears the hover highlight.

Every row has Rename and Delete. Where one cannot act on that workspace, it stays in place and says why when you hover it.

Naming a workspace

Naming one is optional. An untitled workspace is not “Untitled” — it is identified by the directories its panes are in, which is usually the name you would have typed anyway. An SSH pane counts by the host it connects to, so a workspace of only SSH panes is named after its hosts. That name appears in both the picker and the status bar. Give it a title from the picker and it keeps that instead.

You can rename the workspace you are in, and any that is closed. Enter or a click elsewhere saves the new name, and Esc cancels it. One that is open in another window cannot be renamed from here — that window is still saving over it, and would undo the change.

Opening one

From the picker, Enter or a click. If the workspace is already open in another window, TermHQ raises that window to the front instead of opening a duplicate — two windows adopting the same shells would be a bad time for both.

If TermHQ cannot open or bring forward a workspace, the picker stays open and shows the reason, so a failed action does not disappear without explanation.

The command palette lists your other workspaces too — Switch to one that is open in a window, Open one that is not — so you can go straight there without the picker.

However it opens — at launch, from the picker, or brand new — a workspace appears once it is ready: its panes and sidebar fade in together, already in place.

On startup

Settings → Workspaces → On startup decides what happens when TermHQ opens:

  • Resume the most recent workspace — the default.
  • Show the workspace picker — choose every time.
  • Start a new workspace — always begin fresh.

With the picker chosen, it opens at startup in an otherwise empty window. The title bar stays out from under it, so you can still move, minimize or close the window, and a click outside the list chooses nothing. Enter opens the highlighted workspace, and Esc opens the most recent one.

From the taskbar

On Windows, right-clicking TermHQ in the taskbar lists recent workspaces in the jump list. Clicking one opens it directly, or raises it if it is already open. A jump-list click outranks the startup setting — you asked for a specific workspace, so that is what you get.

What a new workspace opens with

One terminal, in your default shell. Settings → Workspaces → Open a terminal in new workspaces turns that off, and a new workspace then opens on the welcome panel instead: New terminal, Find a command, Workspaces, and any favorite directories. You can choose where to work before starting a shell.

If all your panes are stashed, the empty view points you back to the stash shelf instead of making the workspace look as though it has lost them.

The same setting covers any workspace with nothing to restore, not just brand new ones.

Deleting one

The picker offers deletion, and asks first: the row names the workspace, counts its panes, and says its shells will end if it is still running. Cancel has focus, so Enter answers the safe way, and Esc cancels the question rather than closing the picker. Deleting removes the workspace’s saved state and ends any shells still parked for it.

A workspace open in another window can be deleted too: the question says that window will close, and on Delete it closes the way its own close button would, then the workspace is deleted. If that window has unsaved editor work, it comes to the front and asks about it; if it stays open, the workspace is kept and the picker says why. The workspace in the window you’re using can’t be deleted from its own picker.

Deleting a workspace does not touch anything on disk in those directories. It only forgets the arrangement.

Empty ones delete themselves

Close a window with no terminals left in it and that workspace is removed rather than kept in the picker for good — its saved state goes, and so do any shells still parked under it from the undo window.

This is why the setting above is worth knowing about: with a terminal opening automatically, a workspace you opened and closed without doing anything still has that terminal in it, so it stays. Turn the setting off and a workspace you merely looked at cleans up after itself.

A workspace with terminals in it is never removed this way, including one whose terminals are all stashed.

Persistent sessions

https://termhq.dev/docs/persistent-sessions/

Why quitting TermHQ does not kill your shells, exactly what survives what, and the settings that control it.

Closing TermHQ does not end your terminals. They keep running, and reopening the app picks them back up — programs still going, recent output still there.

This is the same promise tmux makes, without having to know tmux.

What survives what

Event Your shells Your layout
Quitting TermHQ Keep running Restored
The window closing while others stay open Keep running Restored
TermHQ crashing Keep running Restored
Sleep or hibernate Keep running Restored
Installing an update Ended; running commands and agents stop Restored, with fresh shells
Restart, shutdown, power loss Ended Restored, with fresh prompts
A program finishing on its own Ended — it finished Restored

A reboot ends running processes. Installing an update also restarts the shells; finish or stop important tasks before choosing Update and restart. When terminals are running in any workspace, TermHQ asks before it goes ahead. What comes back is your arrangement and working directories, with fresh shells. See Updating for the save prompts and restart flow.

SSH panes are the exception in the sleep, update and restart rows. Sleep can drop the connection even though the ssh program itself keeps running, and after an update or a restart an SSH pane comes back disconnected rather than connecting again on its own.

A terminal you have already closed is different too. While its Undo close countdown runs, its shell is still alive, and closing the window or quitting TermHQ ends it there and then, rather than leaving it running out of sight.

Crash resilience is not a setting you have to find. Whatever else is configured, a crash leaves your shells running, because that is the case you would most regret losing.

Coming back

Reopening a workspace reconnects each pane to the shell that was already running in it and replays what it had been saying, so you return to context rather than a blank screen. Panes come back at the size they were, which matters more than it sounds: a shell that drew its prompt at one width and reappeared at another produces mangled output.

Only recent output is kept, not the full history. A pane that comes back emptier than you left it is a pane whose program has been very chatty since.

The workspace appears in one piece. It stays out of sight while its panes are reattached or restarted, then fades in already laid out, sidebar and all — no empty start page first, and no pane arriving on its own. With Settings → Appearance → Animate panes off, it simply appears.

Proportions come back too. If you have dragged a gutter to give one pane more room than another, the workspace remembers that alongside the panes themselves.

Editor panes come back with their tabs

An editor pane restores its tab order and which tab was active. Files load as you need them — the active one straight away, the rest when you first click them.

Unsaved edits are the one thing an orderly quit does not carry across, and that is deliberate: quitting with unsaved work stops and asks first, so leaving it behind is always something you chose. A quit you did not choose is covered separately — see If the app dies instead.

Browser panes come back by address

A browser pane is part of the window rather than of the shell host, so quitting closes its page and reopening navigates back to it. What survives is the address and its place in the grid — plus your logins and cookies, which live in the browser engine’s own profile. “Signed into the dashboard” is still true after a restart; a half-filled form is not.

SSH panes reconnect when you ask

An SSH connection is a pane running your machine’s own ssh program, and that program lives in the background host like any shell. Close the window and it keeps running; reopen and the pane is picked back up with its connection still open, as long as the network held.

What the host cannot do is carry the connection itself through a dropped network, a laptop going to sleep, a reboot or an update. When a connection ends, the pane stays with its output and a card: Reconnect, Open local terminal here or Close. A pane whose ssh program is gone by the time you reopen comes back disconnected, in its place, with the same card.

Nothing reconnects until you ask, so a workspace with five SSH panes does not open with five password prompts. Reconnect, or Enter in the pane, opens a new connection. TermHQ does not keep programs on the far side running across a lost connection.

Several workspaces at once

Workspaces are independent. Closing one leaves the others alone, and one window does not adopt another’s terminals. Installing an update is the exception to window independence: it asks other windows to close and restarts the shells across the app. A window with unsaved edits gets its own save prompt.

A workspace you are not currently looking at is parked, not lost — its shells keep running in the background, and its agents keep working. Press Ctrl+Shift+W and the picker shows you which workspaces are running in the background, so nothing is invisible. Opening one picks its terminals back up mid-task. See Workspaces.

Stashed terminals on resume

A stashed pane is hidden but still running.

By default, a resumed session opens everything into the grid — stash included, and the shelf starts empty. Nothing that was running is left hiding where you would have to remember to go looking for it.

Settings → Workspaces → Stashed panes stay stashed reverses that, sending them back to the shelf on resume instead.

Turning it off

Two settings, under Settings → Workspaces:

  • Keep shells running after close (default on) — turn it off and closing a window ends its terminals there and then.
  • Restore session on startup (default on) — turn it off and every launch starts fresh: a single new terminal, or an empty workspace if you have turned Open a terminal in new workspaces off. Anything still running from last time is ended.

If you want everything gone

Close the panes. That is the reliable route. With Undo close on — the default — a closed terminal’s shell keeps running until its countdown ends, 5 seconds unless you changed it in Settings → General. Close now in the undo list ends it at once, and so does closing the window.

Deleting a workspace from the picker also ends any terminals still parked for it, which is the quickest way to clear out one project’s worth of background work without touching another’s.

Running coding agents

https://termhq.dev/docs/agents/

The parts of TermHQ built specifically for running Claude Code, Codex, and other coding agents.

TermHQ is a terminal, so any agent that runs in a terminal runs in it. These are the parts that exist because of agents specifically.

Launching one in the focused terminal

A terminal pane’s header has an ✳ button listing your agent commands — Claude Code, Codex, OpenCode, Antigravity, Grok Build, Gemini CLI, GitHub Copilot CLI and Cursor CLI out of the box. Like the header’s other tools, it shows on the focused pane, and on any other pane while the pointer is over it. Picking one types its command into that pane’s shell and hands keyboard focus back to the terminal. The menu ends with Manage agents…, which opens Settings → Agents.

A launcher appears once its command is on your PATH, and an install that predates one of them picks it up on its own. Gemini CLI, GitHub Copilot CLI and Cursor CLI must also be the product they claim. A program name can belong to something else — agent is also Grok’s, and copilot is also AWS’s — so TermHQ runs each with --help and checks that it names the right product before listing it. That check passes nothing else, not your configured prompt or flags, and gives up after five seconds. An agent you install while TermHQ is open shows up the next time the window comes to the front, when Settings or the agent picker opens, or when you press the refresh button in Settings → Agents. With none found, the button stays, dimmed, and takes you to Settings → Agents to set one up. A pane whose shell has ended has no agent button, since there is nothing to type into, and neither has an SSH pane: the agents TermHQ found are on this machine, and the command would run on the far host.

Use a terminal at an idle shell prompt. Finish or clear any partially typed command first, and do not launch into a program that is already using the terminal. To keep that program running, launch the agent in a new pane instead.

Where the shell reports each prompt to TermHQ — as PowerShell, Command Prompt, Git Bash and WSL’s bash do on Windows — TermHQ catches the most common slip for you. If the agent it last launched in a pane is still running there, because the shell has not shown a prompt since, a second launch opens a new pane with the same shell and folder and starts the agent in that, instead of typing the command into the running agent.

In any shell, a second launch into the same pane within three seconds is not sent at all, so a double click never types the command twice; the pane says Sent a moment ago · one command every 3 s.

The list is yours to edit in Settings → Agents → Agent launchers, flags included, so claude --dangerously-skip-permissions is one click rather than something you retype all day. Each row shows the number the agent answers to, its mark, its name, whether its command was found — found, not on PATH, not verified (found, but not the product it’s named for; its hint says why), or checking… — and the command itself. Add agent starts a new row; drag a row by its grip to reorder, or focus the grip and use the arrow keys; removing one asks Remove? first. Entries whose program is not on your PATH are hidden from the menus automatically, so a launcher missing from the menu is explained where you would look for it. If the numbered picker has no available entries, the command palette tells an empty agent list apart from agents it could not find on your PATH.

Command detection on macOS

Opening TermHQ from Finder or the Dock should find the same agent CLIs as your terminal. TermHQ reads the PATH from your interactive login shell and caches it, including paths added by Homebrew, npm and shell startup files. IDE and file openers use that resolved path too. The initial launcher lookup runs in the background so it does not hold up the interface.

If you change your shell’s PATH while TermHQ is open, restart TermHQ so it reads the new one; an agent installed into a folder already on it is found without a restart. On Windows, TermHQ uses the path in its process environment plus any folders an installer has added since, so a new install is found without restarting.

Launching one in a folder or worktree

You do not need to open a terminal first. Anywhere TermHQ offers an Open in <shell> list — a folder in Files, a favorite, or a row in the global Worktrees view — open the flyout on the shell you want: click the chevron at the row’s edge, right-click the row, or press → on it. The flyout lists the installed agents under the same marks as the pane-header launcher. Pick one and TermHQ opens that shell in the selected folder, then starts the agent in it.

A click on the row itself still opens only the shell. The agent list waits behind the chevron so the ordinary “open a terminal here” action stays unambiguous.

The arrow beside the + button in the title bar opens the shell menu, which reaches the same place without the Files panel: a shell’s flyout lists your favorite folders, and a favorite’s flyout lists the agents to start there.

By number, without the mouse

Several agents across several panes should not mean a trip to a dropdown for each. Ctrl+Shift+A then a digit runs an agent in the focused terminal: 1–9 and 0 for the tenth, in the order the list is arranged in Settings. While it is armed, a card lists the numbered agents so the mapping is never guesswork, and its title names the terminal the command will be typed into; Esc cancels.

Only installed agents are numbered — the same PATH filtering as the dropdown, so the numbers always match what you can see. Both the number row and numeric keypad work, including 0 for the tenth entry.

The chord needs a terminal with its shell still running, since what it does is type a command into it. With an editor or a browser pane in front, a terminal whose shell has ended, or an SSH pane, it does not open a picker that could not work: the key goes on to the pane, and the command palette’s Run an agent by number row says why.

The command palette also lists each installed agent by name — Run Claude Code and the like — to type into the focused terminal.

When a pane needs your attention

The problem with running several agents is not starting them, it is noticing when one stops.

A pane that was busy while you were looking elsewhere and has since gone quiet gets a pulsing header: the icon at its left that shows what kind of pane it is pulses in the theme’s attention color, and an inset wash and the bottom hairline breathe with it. A stashed terminal moves to the top of the stash shelf under Waiting on you, with the time it went quiet, and its row glows the same way, so a parked job can still get your attention. This works for longer-running commands as well as coding agents.

Waiting panes collect in the bottom status bar as a count — N waiting — that stays as long as anything is waiting. For a few seconds after a new pane goes quiet, a chip joined to its left names that pane under a draining bar; click the chip to jump straight to it. Click the count to open the list, newest first. Each entry shows the time the pane went quiet — waiting since 2:45 PM — and whether it is in the grid or in the stash shelf.

Click an entry to focus that pane, restoring it from the shelf or bringing it back into view if another pane is maximized. From the keyboard, Tab to the count and press Enter: the list opens with focus on its first entry, ↑ ↓, Home and End move between entries, and Enter or Space jumps. An entry’s Dismiss button removes only the notice; it does not close the pane or stop its work. With more than one waiting, Dismiss all clears every notice at once. Esc closes the list without clearing it.

Ctrl+Shift+N — Jump to the newest waiting pane — goes straight to the pane that went quiet most recently, the first entry in the list, without opening it.

Notices do not expire on a timer. Returning to the pane, dismissing its notice, or closing the pane clears its entry. The waiting item disappears when the list is empty by default. To keep it visible, enable Settings → Agents → Always show it, even when nothing is waiting. It then reads 0 waiting, and opening the empty list shows Nothing waiting right now.

When TermHQ is in the background, the same trigger also sends a native OS notification, and the in-app entry is waiting for you when you return. Show waiting panes in the status bar in Settings → Agents controls both kinds of notification; Agent idle badge controls the pane and shelf highlights separately.

TermHQ ignores the echo of your own typing, work you watched happen, and jobs over in under three seconds. A fresh terminal’s startup output does not trigger a waiting notice before you run a command or launch an agent in it.

Quiet does not necessarily mean finished or successful. An agent may be thinking or asking for input. Read the pane’s output to confirm its state. The default quiet period is 10 seconds; increase Quiet seconds before badge in Settings → Agents if an agent is being flagged during normal pauses. That threshold also applies to waiting notices.

Agents come up in color

Coding agents often render monochrome inside other terminals, and the usual culprit is not the agent. When one tool launches another, environment variables leak: a NO_COLOR=1 set by whatever started your terminal is inherited by every shell it spawns, and well-behaved programs obey it.

TermHQ scrubs those leaked variables on every shell it starts and sets the capability variables that say color is supported. Agents come up in color because the environment they are handed is correct, not because TermHQ special-cases any particular tool.

Panes are born at their final width

A pane is created at the size it will be displayed at, so a shell’s startup output — and an agent’s first banner — is composed for the width you will read it at rather than reflowed afterwards.

Watching several at once

Tiling is the point. Agents working means panes visible, not tabs where all but one are hidden. There is no cap on how many — the grid keeps growing, and when it gets busy you can park the ones you are not watching without stopping them.

Each pane’s font size is independent, so an agent producing a wall of output can be small while the shell you type in stays comfortable.

Watching what an agent is building

An agent building a web app is producing something you have to look at, and alt-tabbing to a browser window is how you lose the pane it is working in. Ctrl+Shift+B opens a browser pane in the grid instead — point Settings → Browser → New panes open at localhost:3000 and every new one lands on your dev server. Drag the boundary between it and the agent’s terminal to give the page the width it wants; a web page has a natural width and a terminal does not.

Long jobs survive you leaving

Agents run long. Because shells live in a separate process (Persistent sessions), you can quit TermHQ while an agent is mid-task and pick it up later with its output intact.

Installing an update restarts the shells, however. Finish important jobs before choosing Update and restart; see Updating.

Directory awareness

TermHQ knows which directory each pane is in, and keeps up as the shell moves around. The file panel follows the focused pane, so it is already showing the folder the agent is working in rather than your home directory. So does Source Control — repository, branch, changes, staging, commits and history for whichever pane you are looking at, which is how you review and ship what an agent just did without leaving the app.

If you use separate Git checkouts for parallel tasks, the global Worktrees view keeps them grouped by repository and puts a terminal or agent action directly on each one. It shows checkout state without guessing whether an agent is running there.

Files follows WSL directories too. Source Control does not yet support repositories reached through WSL paths; use Git in the WSL terminal for those.

The </> button in the pane header opens that directory in your editor, for the moments when the right move is to take over by hand. For a smaller intervention — one line in a config, a typo in a prompt file — an editor pane opens the file right there in the grid, beside the agent that is waiting on it. A file an agent rewrites while you have it open reloads on its own, or asks first if you have unsaved edits of your own.

Dictating to an agent

Prompts are long, and typing them is the slow part. TermHQ’s dictation types into the terminal you started it in, so you can talk a prompt at an agent and edit it before sending — and click over to another pane while it transcribes without the words following you. Opt in to Hold to talk and holding the space bar for a moment is the whole gesture, the way Claude Code’s own dictation works, for every program; rebind it to a key of its own (Right Ctrl, say) and Claude Code’s keeps working beside it.

Transcription happens on your machine, on a local Whisper model you pick and download once in Settings → Voice (or bring your own) — which matters for a tool sitting in front of proprietary source. English by default, fifteen other languages in the same panel. Linux support is pending. The whole feature has its own page: Dictation.

Keeping their keystrokes theirs

Agents with full-screen interfaces want chords TermHQ also uses. Ultra focus hands the terminal every key unmodified; only its own toggle and Ctrl+Shift+V, which pastes, stay TermHQ’s. See Keyboard shortcuts.

Dictation

https://termhq.dev/docs/dictation/

Talk into a terminal, a text field or a web page: on-device transcription with a local Whisper model, started from a button, a chord, or a held key, with a cursor that shows it listening.

TermHQ types what you say into a terminal, into one of its own text fields, or into a text field on a web page in a browser pane. Transcription happens on your own machine, on a Whisper model you download once — nothing is sent anywhere, which matters for a terminal sitting in front of proprietary source. It exists because prompts to coding agents are long and typing them is the slow part, but it works at any shell prompt.

Before the first word

The installers ship without a speech model, so a fresh install shows no mic button at all. Open Settings → Voice, download a model (or import one you already have), close Settings, and the button appears in the title bar. The panel says at the top whether dictation can run on this build and whether a model is ready, before it offers anything to download. Installation covers the models and their sizes; Test microphone in the same panel plays a few seconds back through the exact capture path dictation uses, so a silent microphone is found before any words are spent on it.

Keep Settings open while a model downloads: closing it cancels the download. Press Esc, click its close button or click outside it mid-download and TermHQ asks first — Keep downloading, or Close and cancel it.

Linux support is pending.

Three ways to start

  • The mic button in the title bar. Click to start, click again to stop. The words go to the focused terminal, or to the text field you were typing in when you clicked.
  • The chord, Ctrl+Alt+Space on every platform — the one shortcut that does not move to ⌘ on macOS, because ⌘+Alt+Space is Finder’s search. It works in a terminal, in TermHQ’s own text fields, and over a web page in a browser pane.
  • Hold to talk, off by default. Turn it on under Settings → Voice and holding the space bar in a terminal for a moment starts dictating; let go and it transcribes — the gesture Claude Code’s own dictation uses, here for every program. A tap still types a space, and a key pressed mid-hold flushes the space ahead of it, so typing is unchanged.

Stopping — a second click, the chord again, or letting go of the held key — sends the recording to the model. The button and the chord stop a recording even if you have clicked into another terminal, an editor or a text field since. The exception is ultra focus, which hands the chord to the terminal — use the button there. A recording under 0.4 seconds is dropped rather than transcribed.

The key you hold

Space is the default because it is the key Claude Code uses, and that is also its cost: while Hold to talk is on, holding the space bar inside Claude Code starts TermHQ’s dictation instead of Claude Code’s. If you want both, give TermHQ’s a key of its own. Settings → Voice → Hold key shows the current key; click it and press the one you want — any single key, a modifier such as Right Ctrl included, which is the classic push-to-talk key. Esc keeps the current one. A quick tap of the key still does what it normally does: a character key types its character, a modifier or function key tapped alone does nothing.

The hold is not a shortcut in the usual sense — it is a hold, not a chord — so it lives in Settings → Voice rather than in Settings → Shortcuts.

Where the words land

In a terminal, the transcript is typed into the terminal you started dictating in, not into whichever pane happens to be focused when the model finishes. Start in one pane, click into the next while it records or transcribes, and the words still arrive in the first. Dictate twice into the same prompt without typing in between, and the second lands after a space so the two do not run together.

In a text field — the commit box, a search box, a browser pane’s address bar — the words go in at the cursor, replacing any selected text, with a space in front where they would otherwise run into the word before. The field takes them as if you had typed them.

On a web page in a browser pane, the words go into the text field the page had focused when you started — a search box, a comment form, a chat input — typed through the page’s own editing, so the site sees ordinary typing and its own undo takes them back. They go where you started even if you click elsewhere while they are being transcribed, with a space in front where they would otherwise run into the word before. A page with no text field focused has nothing to type into, and dictation says so before the microphone opens.

Anywhere else there is nothing to type into: an editor, a terminal whose shell has ended. There dictation does not start. The mic button says Nothing to dictate into in the status bar, and the chord goes on to the pane like any shortcut with nothing to do.

Nothing is submitted for you. The words appear at the prompt as if typed, and Enter is yours to press — read them first.

The cursor shows it

While a recording is aimed at a pane, that pane’s cursor becomes a block that shows what is happening. Recording: a bar inside the cell rises with your voice — gray in a quiet room, cycling through color the moment it hears you, tuned so a quiet microphone still swings most of the cell. Transcribing: a chrome block with the light traveling upward, in time with the mic button’s three dots and the Transcribing… label in the title bar. The block follows the cursor as the shell moves it and disappears the moment the words land.

Reduced-motion settings still the animations and keep the block.

When it fails

A dictation that cannot finish says why in the status bar, and the message’s tooltip says what to do:

The status bar says What to do
Dictation: The microphone is blocked Allow microphone access for TermHQ in the system’s privacy settings, then try again.
Dictation: No microphone was found Plug one in, or pick another in Settings → Voice.
Dictation: The microphone is busy Another app may be holding it — close that app, then try again.
Dictation: The microphone could not be opened The tooltip carries the system’s own reason.
Dictation: No speech model is installed Download one in Settings → Voice.
Dictation: Nothing was heard Speak a little longer, or check the level with Settings → Voice → Test microphone.
Dictation: Transcription failed The tooltip carries Whisper’s own error.

Beside the mic button, Dictation failed shows for a moment at the same time.

Language and models

Dictation listens in English by default. Settings → Voice → Dictation language offers fifteen more and an auto-detect option that lets a multilingual model identify the language per recording; models labeled English only stay English whatever this says. Models can be switched, deleted or re-downloaded at any time, and they survive updates.

When something is wrong — no button, a flat waveform, the wrong words — see Troubleshooting.

Source control

https://termhq.dev/docs/source-control/

Review, stage and commit changes, browse history, manage branches, sync, resolve conflicts, and work with stashes and worktrees.

Open the Git tab in the sidebar — or run “Git: Open the Git panel” from the command palette — to work with the repository belonging to the pane you are focused on. Move to a pane in another project and the panel follows it, just like Files. The tab counts the files that changed; while files are conflicted, a badge with their count takes its place (Settings → Git → Conflict count on the Source Control tab turns the badge off).

A browser pane or an SSH pane has no local folder, so the panel does not follow one: while it has focus, the panel shows the repository of the folder the Files tab is on. The Pin beside the sidebar’s “Following …” line holds the panel on one folder’s repository whatever you focus, and the palette’s Git actions and the conflict badge follow the pin too.

One band across the top holds the repository’s name, its branch, and the sync controls. Under it are two views:

  • Changes is the working view: changed files, staging, commits, conflicts, stashes and worktrees.
  • History opens the commit graph and its search and file-history tools.

The refresh button beside those two reads the repository again right away instead of waiting for the next check.

Review and stage changes

Files are grouped as Merge Changes, Staged Changes, and Changes; click a group’s header to fold it. A partly staged file appears in both staged and unstaged groups, so the panel never hides the part you have not committed yet — its staged row carries a half-filled circle to say so.

Each row shows the file’s status letter, its icon and its name, with its folder dimmed after it. The row’s actions appear as icons when you hover or focus it: open the file, discard, stage or unstage. Right-click any row for the full set — Open the diff, Open the file, Stage or Unstage, Discard changes…, File history, Copy path, and Reveal in File Explorer (Reveal in Finder on macOS). The group headers carry stage all, unstage all and discard all.

The file list takes a single Tab stop: the arrow keys, Home and End walk its rows, and Enter opens the one you are on. A group with more than 300 files shows the first 300 and a Show all button with the count. A submodule is a repository rather than a file, so clicking it opens a terminal inside it instead of a diff.

A discard confirmation tells you what the file will return to. Untracked files go to the operating system’s recycle bin or trash rather than disappearing permanently.

Click a file to open its diff. It opens on the first change; step through the rest with the arrows either side of the Change 1 of 7 list, or pick one from it. From an unstaged diff, click a change’s gutter mark — or Stage change — to stage just that hunk; from a staged diff, the same gesture unstages it. Stage the last change and the overlay says All staged., with Next file to move on. The overlay’s header also stages or unstages the whole file, discards its changes (asking first), steps to the previous or next file in the group, and switches that diff between side by side and stacked; Settings → Git → Diff layout chooses which one diffs open in. If the file changed after the diff opened, TermHQ refreshes instead of applying an action to stale content.

Binary files and files too large to preview are labeled rather than shown as garbled text. New files appear as additions, and deleted files can be staged as a whole.

Commit what you staged

The main Commit button records exactly what is in Staged Changes, and shows how many changes that is. Ctrl+Enter (⌘+Enter on macOS) commits from the message box without reaching for the pointer. The box starts at one line and grows with your message, up to eight.

While a commit runs — your hooks, a signing prompt — the button reads Committing… and the box is read-only, so the same commit cannot start twice. A finished commit shows as a brief note rather than a banner.

If the repository cannot be committed, the reason appears below the box — for example, nothing is staged, conflicts remain, or an operation is in progress. Beside “nothing staged”, Stage all and commit does both at once. The menu beside Commit also offers:

  • Commit All (stage everything first) — stages every change, untracked files included, then commits it.
  • Amend Last Commit — switches the box to amending, marked by a chip above it. An empty box gets the last commit’s message, and a note warns that a commit you already pushed will need a force push. The chip’s × returns to a normal commit and brings back the draft you had before.
  • Undo Last Commit — asks first, then removes the latest commit while leaving all of its changes staged. Your files are not lost; the commit’s message returns to an empty box, and a draft you were writing is kept.

Browse history

Choose History to see the repository’s commit graph. Each row shows its branches and tags — two at most, then a count such as +2 — its author with their picture, the message, and a relative time. The header counts what is loaded, such as “100+ commits” while there is more to scroll to. The arrow keys move between commits, and Home and End jump to the ends of what is loaded.

Select a commit for its full message — selectable, so you can copy from it — and its changed files, then open any file to compare that version with its parent. The diff opens on its first change, and the arrows either side of the Change 1 of 7 list step through the rest. From a commit’s diff, open current file opens the file as it is in your working tree today, not that commit’s version.

Committer pictures come from GitHub for noreply addresses and from Gravatar otherwise, cached after the first fetch; Settings → Git → Committer pictures in History turns the lookups off and shows initials instead.

Search accepts message text, author:name, or a commit ID. The graph is a snapshot, so new commits never shift the history you are reading; if HEAD moves while it is open, a banner says so. Refresh reads the graph again from the current tip.

From a selected commit you can copy id, branch from here, or — when TermHQ recognizes the remote’s host, such as GitHub or GitLab — open on that host, which opens the commit’s page in a browser pane. File history follows a file through renames and shows the path it had at each commit. Open it from a changed file’s right-click menu here, or from any file’s right-click menu in the Files panel.

Branches and syncing

Click the branch in the top band for a searchable picker, with Local and Remote branches in sections of their own and the most recently committed first by default (Settings → Git → Branch order). Each row shows its last commit’s subject, and the branch you are on is badged current. From it you can:

  • switch to a local or remote branch
  • create a branch by typing a new name
  • rename or delete a local branch
  • see when a tracked upstream branch is gone

Deleting a branch asks first, and a branch that is not fully merged asks a second, explicit time. If uncommitted changes block a switch, the message that says so offers Stash and switch: it stashes them, untracked files too, switches, and leaves the stash in the list.

Fetch, pull, and push sit at the end of the top band, with ahead and behind counts when there is something to push or pull. Fetch has an icon of its own, and each of them spins while it runs. The counts are only as fresh as the last fetch, so their tooltips say when that was — and Pull stays enabled even when the last count said there was nothing to pull. Push is disabled when there is nothing to push. A branch without an upstream offers Publish, which also spins while it works. TermHQ follows your Git configuration when choosing a remote, and when several remotes leave no clear choice, it says so rather than guessing.

Pull is fast-forward-only by default, so a diverged branch stops instead of creating a surprise merge. You can choose rebase or merge in Settings → Git → Pull style. After a rejected push, the panel can offer Pull with rebase. A force push is available only with a protective lease: if someone else updated the remote after the version you confirmed, the push stops rather than overwriting their work.

Resolve conflicts

An in-progress merge, rebase, cherry-pick, or revert gets a banner that says what is happening and how many files still need a decision. Continue, Skip where supported, and Abort are available in the same place; Abort confirms what it will discard.

Select a file under Merge Changes to open it in an editor pane. Each conflict block offers Accept Current, Accept Incoming, or Accept Both, and you can edit the result normally. When it is done, Mark resolved on its row stages it — asking first if conflict markers are still in the file. The labels stay tied to Git’s own sides during a rebase, where “current” and “incoming” are easy to read backwards.

You can also compare the two sides of a conflict, or choose copy AI prompt on the Merge Changes header. That copies a concise briefing — affected files, which side is which, and the instruction to resolve and stage without committing — ready for whichever AI you trust.

Stashes

Stash your working changes with stash… on the Changes header — it appears only when there is something to stash — or with “Git: Stash Changes” in the command palette. The message is optional, and the untracked box starts ticked, so files Git is not tracking yet go into the stash too.

The Stashes section lists what you have. Expand a stash to review its files, untracked ones included, and open their diffs, then apply, pop, or drop it. Each action works on exactly the stash you picked: if the list changed since it was shown, TermHQ reads it again and asks you to try once more instead of touching a different stash. Dropping confirms first because those changes may exist nowhere else.

Worktrees

The Worktrees section lists the repository’s working folders. add worktree… creates one on a new branch: type the branch name and the folder beside it fills in to match, until you edit the folder yourself. Enter creates it, and the button reads Creating… while Git works. Every other checkout has a button that opens a terminal there. Removing a linked worktree asks first — its folder is deleted, while the branch and its commits stay — and one with uncommitted changes asks a second time, with Force remove, because those changes would be lost.

For a view across several repositories, add one or more folders under Settings → Git → Worktree roots. A Worktrees item then appears in the status bar, grouping every checkout it finds by repository and putting a terminal, agent, IDE, or file-manager action on each row. See the complete Worktrees guide.

Command palette and errors

The command palette has the panel’s actions by name, each starting with “Git:” — open the Git panel or History, commit, stage or unstage everything, fetch, pull, push, switch branch, stash, and refresh. None has a keyboard shortcut by default, so they take no keys away from your shells.

When Git refuses an action, the message appears beneath the repository header with a plain-language summary and suggested next step, and its text can be selected and copied. Expand it when you need Git’s complete response. Background fetch failures stay quiet while their ahead/behind counts are marked stale, so going offline does not produce a new warning every few minutes.

TermHQ uses the git already on your PATH, along with your configuration and credential helpers. Repositories reached through WSL paths are not supported yet; see Troubleshooting.

When there is no repository to show

  • If the first read of a folder fails — Git missing or too old, a permissions problem — the panel says Source Control can’t read this folder, gives the reason, and offers Retry. When the cause looks like a missing or old Git, it adds that Source Control needs git 2.23 or newer.
  • Outside a repository, the panel says No repository here, names the folder, and offers Initialize repository…, which runs git init there after asking. The question starts on Cancel, so a click by mistake followed by Enter changes nothing.
  • A clean working tree says so, and offers View history.

Elsewhere in the app

  • While the sidebar is open, the status bar shows the branch of the repository the Git panel is showing — at its left, after the Worktrees item if you track worktrees. Beside it, a dot in your theme’s color counts changed files, and the push and pull arrows count commits ahead of and behind the upstream; hover it for the counts in words. Click it to open the Git panel. Settings → Git → Counts beside the branch in the status bar turns the counts off and keeps the branch.
  • Switching between the Files and Git tabs keeps your commit message, amend mode, and a push, pull or commit that is still running.
  • A file’s right-click menu in the Files panel has File history, which opens that file’s history here.
  • Inside a repository, the Files tree tints and letters changed files — see The editor.

Worktrees

https://termhq.dev/docs/worktrees/

Keep several checkouts organized, open a terminal or agent in the right one, and track worktrees across repositories.

A Git worktree is another working folder for the same repository. It lets you keep one branch open while another branch — or another coding agent — works in parallel, without switching the files underneath either task.

TermHQ gives you two views of them:

  • The Worktrees section of the sidebar’s Git panel manages worktrees for the repository belonging to the pane you are focused on. A browser or SSH pane has no local folder, so the panel does not follow one.
  • The Worktrees item in the status bar shows checkouts across every folder you chose to track, no matter which pane is focused.

Track worktrees across repositories

Open Settings → Git → Worktree roots and add the folders that contain your repositories or worktrees. Type a path, or use Choose folder… to pick one with the system dialog. A folder that cannot be read is refused when you add it, with the reason.

As soon as at least one root is set, Worktrees appears at the far left of the status bar with the number of checkouts found. It comes first in the bar, ahead of the focused repository’s branch, so it stays put while the branch beside it changes with every pane you focus. No root means no scan and no status-bar item.

The scan looks for Git checkouts up to two levels beneath each root, which covers both common arrangements:

root/project
root/project/worktree

It does not crawl the rest of your machine. If one checkout belongs to a repository whose primary folder sits outside your chosen roots, TermHQ includes that folder in the repository group and labels it outside roots rather than searching beyond the roots.

Reading the Worktrees view

Click the status-bar item to open the full list. Its header sums it up — “12 checkouts · 5 repositories” — and once there is more than one checkout, a filter box narrows the list to the repositories, branches or folders matching what you type.

Checkouts are grouped by repository, with each repository open by default. Fold a group with a click, Enter, or ←; → opens it again. The folded state is remembered until that TermHQ window closes.

Each row shows:

  • whether it is the primary checkout or a linked worktree
  • the branch, or a detached-head label
  • the folder path
  • badges for what else is true: changes, detached, locked, folder missing, or outside roots

After the view opens, TermHQ checks the worktrees one at a time. The changes badge appears as each checkout is checked, so a long list can become useful immediately instead of making you wait for every folder.

A plain clone is labeled primary. Folders created with git worktree are labeled linked. “Primary” describes its role in Git; it does not assume the branch is named main.

Open the right terminal or agent

Double-click a checkout, select it and press Enter, or use its terminal button to open your default shell there. If TermHQ already opened a terminal for that checkout, the same action focuses it instead of creating another one.

Open the row menu with ⋯, right-click, or Shift+F10 to:

  • choose a different installed shell
  • open the folder in your IDE or file manager
  • copy its path
  • remove a linked worktree

When the row’s ⋯ button has keyboard focus, Enter opens that menu; it does not fold the repository group or open a terminal. With a checkout row selected instead, Enter keeps its open-or-focus-terminal action.

To start an agent there, open the row menu and right-click an “Open in <shell>” row, or click the chevron at its edge. Pick one of the installed agents from the flyout. TermHQ opens that shell in the checkout and starts the agent in it.

Every removal asks first, and says what it means: the worktree’s folder is deleted, while the branch and its commits stay. Answer Keep it or Remove worktree. A checkout with uncommitted changes gets a second, separate question, because those changes would be lost — Force remove is the only way past it. The primary checkout is never offered for removal here, and a worktree whose folder is already gone cannot be removed from the list — git worktree prune drops its entry.

Refresh and change the roots

The view refreshes when it opens, when TermHQ creates or removes a worktree, and when you return to the app, at most once every two minutes. Use Refresh when you want an immediate scan. While a refresh runs, the status bar keeps the last count in place and turns its Worktrees mark into a spinning refresh symbol.

The gear in the Worktrees header opens Settings → Git → Worktree roots directly. Removing a root there asks Remove? first, and only stops tracking it; nothing on disk is changed. A root that has moved or disappeared stays in the list: the status-bar item turns to a warning, and the Worktrees view names the root it could not read, so you can repair or remove it.

Press Ctrl+Shift+T, or choose Worktrees from the command palette, to open the view without the pointer. On macOS, use ⌘+Shift+T.

An editor pane keeps that chord for Reopen closed tab while the editor is focused. Click the status-bar item, focus another pane, or turn off Settings → Editor → Editing shortcuts stay in the editor when you want the Worktrees view instead.

Repository worktrees in the Git panel

For the repository you are already reviewing, open the Worktrees section in the Git panel’s Changes view. You can create a sibling checkout on a new branch, open a terminal in an existing one, or remove a linked worktree without leaving the panel — with the same questions before a removal.

The global tracker is a view across repositories; it does not replace this repository-specific section.

What the tracker does not infer

The list tells you where checkouts exist and whether they have changes. It does not claim that an agent is running in a checkout. A terminal TermHQ opened from the list can be focused again, but the app does not inspect processes and guess which tool may be working there.

Configuration

https://termhq.dev/docs/configuration/

Where TermHQ keeps its settings, every setting you can change, and how config files behave across versions.

Everything configurable lives in Settings. Ctrl+P (⌘+P on macOS) opens it with the search box already focused, so you type the setting you want instead of hunting through categories. The same chord — or Esc — closes it.

Search accepts several words in any order, such as Interface scale or scale interface. You can combine a category with a setting name, and options inside collapsed advanced sections remain searchable. If nothing matches, Clear search takes you back to the settings list.

The categories run General, Workspaces, Appearance, Terminal, Browser, SSH, Editor, Agents, Git, Voice, Files and Shortcuts — the order this page follows. Each one groups its settings into cards, and on/off settings are switches.

Settings are written to a JSON file you can also edit by hand.

Where it lives

Platform Path
Windows %APPDATA%\dev.termhq.app\config.json
macOS ~/Library/Application Support/dev.termhq.app/config.json
Linux ~/.config/dev.termhq.app/config.json

Alongside it, in the same directory:

Item Contents
themes/ Your own and imported color themes, plus the commented _template.jsonc
icons/ Installed file-icon themes
backgrounds/ The pictures and videos you added as backgrounds — copies, so they keep working when the originals move
logos/ Cached artwork for installed marketplace extensions, so the Installed list has pictures offline
models/ Downloaded and imported speech models for dictation
sessions/ One JSON per window slot: the saved state of each workspace
recovery/ Unsaved editor text, mirrored so a crash cannot take it
avatars/ Committer pictures for Source Control’s History, cached after the first fetch
ssh-profiles.json Saved SSH profiles and recent targets — hosts, users, ports and key file paths, never a password, passphrase or key
config.json.broken-… A settings file TermHQ could not read, kept aside under the UTC time it was found (see below)
pty-host.log A log file, useful to attach to a bug report

Missing keys are filled in

Any key absent from config.json takes its default. A config written by an older TermHQ keeps working after an update — new settings appear with their defaults rather than the file needing a migration, and hand-editing cannot break startup by leaving something out.

The same applies in reverse: a key TermHQ no longer recognizes is ignored, and dropped the next time the file is written.

An unreadable file is kept

A file that is not valid JSON — or holds a value of the wrong type — does not stop TermHQ from opening. It starts with default settings, keeps your file as config.json.broken- followed by the UTC time, such as config.json.broken-2026-09-23T101500Z, and shows Your settings file couldn’t be read with the error, where the copy went, Open folder and Dismiss. Nothing you had is lost: with TermHQ closed, fix what the error points to and put the file back as config.json.

If the file stops parsing while TermHQ is running, the next saved change keeps a copy the same way before it writes a fresh file.

Editing by hand

A change you make in Settings saves only the keys that changed. TermHQ re-reads config.json, replaces those keys and writes the file atomically, so a hand edit to any other key survives.

A change also reaches every open window immediately — change the theme, a favorite or a shortcut in one workspace and the others follow. Three things stay with each window: whether the sidebar is showing, its extra width, and the Grid or Columns layout. They still save, as the starting point for the next new window, but they never rearrange a window you are working in.

Open windows do not re-read the file, though. A hand edit takes effect the next time TermHQ starts, and a key you edit by hand while it runs is overwritten if you then change the same setting in the app. Closing TermHQ first is still the simple way to edit it.

If a save fails, the change stays active in the window and TermHQ says Settings weren’t saved, with Retry — at the top of Settings, and in the status bar once Settings is closed.

Keys are camelCase.

What you can change

General

  • Default shell — used by the + button, Ctrl+J and favorites. Unset means the first shell detected.
  • Undo closing a terminal — which close paths park a terminal instead of ending it: Shortcut and the pane’s × button (the default), Keyboard shortcut only, or Off — close immediately. A parked terminal keeps running out of sight, so Undo close in the status bar brings back the program and its scrollback exactly as they were.
  • Undo window — shown while undo is on: how many seconds, 3 to 60, a parked terminal waits before its shell is actually killed. Default 5.
  • When a shell exits on its own — keeps failed shells’ panes open by default so you can read and copy their output. Press Enter to close the ended pane. You can choose to always keep ended panes or always close them instead.
  • Clone keeps directory — whether duplicating a pane opens in the source pane’s directory or at home. Default on.
  • Sidebar (files & git) — whether the Files and Source Control sidebar is showing. This switch, the sidebar button beside Settings in the title bar and Ctrl+B (⌘+B on macOS) are the same switch, and wherever you leave it is where the next launch starts. It also follows the grid on its own: the file tree reads the focused terminal’s directory, so it leaves when your last terminal does and comes back with the next one. Switching it off yourself outranks that — it then stays shut, including while you move between terminals, until you switch it back on.
  • Sidebar side — left or right. The sidebar button in the title bar mirrors itself to show which side the sidebar occupies.
  • Sidebar extra width — gives the Files and Source Control sidebar more room, up to 338 extra pixels before interface scaling. Drag its inner edge to resize it, or use this slider. The original width is the minimum, the maximum adapts to narrow windows, and your choice is remembered. Double-click the edge to reset; with the edge focused, use the left/right arrows to resize, Home to reset or End for the maximum. Its highlight appears after a brief hover, so passing over the edge does not light it up.
  • Favorite directories — your starred directories, in order. Drag a row by its grip, focus the grip and use the arrow keys (Home and End jump to either end), or use the up and down buttons. Add folder… adds one through the system’s folder dialog and says so if it already is a favorite. Removing one asks first: the × turns into a red Remove?, and only that click removes it. One order drives the title bar dropdown, the welcome list and the number keys — only the first ten get a number — so there is never a second ordering to keep in sync. Favorites are stored shell-agnostically: opening one spawns whatever your default shell is at the time you click, not the one that starred it.
  • Check for updates automatically — under Updates, on by default. Checks shortly after launch and every six hours while the app runs. Check now checks on demand, including when automatic checks are off. An available release offers Update and restart; installation requires your click and stops running commands and agents. The same card shows the Version you are running, the one to quote in a bug report. See Updating.
  • Send startup reports — under Privacy, on by default. Each start sends one anonymous report naming only the operating system and the app’s version, which is how launches are counted. Off sends nothing, cancels a report still on its way, and stays off for every later start. See What reaches the network.

Grid or Columns is not a row here. It is the switch in the title bar, or the Switch between Grid and Columns action — unassigned by default, so bind it under Shortcuts or run it from the command palette. Each workspace keeps its own mode; the layout key in config.json is only the mode a new window starts in, and it is not synced to windows already open.

Workspaces

  • On startup — resume the most recent workspace, show the picker, or start a new one. Default: most recent. A taskbar jump-list click overrides it for that launch.
  • Open a terminal in new workspaces — whether a workspace with nothing to restore starts with one default terminal or on the start panel. Default on. Turning it off is also what makes a workspace you opened, looked at and closed clean up after itself, since a workspace closed with no terminals in it is deleted rather than kept.
  • Restore session on startup — reopen your last panes with their shells, directories, layout, zoom and titles. Default on. Off means every launch starts fresh — with one default terminal, or empty if you turned the setting above off — and anything still alive from last time is ended.
  • Keep shells running after close — closing the window leaves its shells running in the background, and the next launch picks them up. Default on. Needs session restore to do anything.
  • Stashed panes stay stashed — see Persistent sessions. Default off.

Appearance

  • Interface density — Compact keeps the default spacing; Comfortable gives buttons and rows larger click targets. Neither changes terminal or editor text size.

  • Interface scale — 100% (default), 110%, 125% or 150% for app labels and controls. Terminal fonts, editor fonts and browser-page zoom keep their own settings. Density and scale work with every theme.

  • Dim unfocused panes — default off. Washes every pane but the focused one toward the theme’s background, so the one you are typing into stands out even in a theme whose focus edge is subtle. The dimmed panes still take clicks.

  • Theme and Terminal theme — the second can point at a different theme, so the terminal palette and the interface need not match; Match app theme keeps them together and leads its list. Both lists start with the built-in themes, Default first, then each installed pack. Both are searchable; see Theming for previews and theme-pack variants. Manage themes → Marketplace & installed… opens the Marketplace, a page inside Settings for theme packs from Open VSX; Back or Esc returns to Appearance.

  • Background — a picture, a GIF or a looping video behind your terminals. The card shows your backgrounds as tiles: None, each one you have added, and Add…, which copies a file into your backgrounds/ folder and applies it. Pictures can be PNG, JPEG, WebP, GIF, AVIF or BMP, and videos MP4, WebM or M4V, up to 1 GB. Videos play muted and looping, and pause while the window is hidden. A tile’s × deletes that file from the folder, after the same Remove?. Files you drop into the folder by hand are listed too. One background serves every workspace, like the theme. Once one is chosen, these appear:

    • Transparency — how much of the background shows through the terminals, 0–100%, default 25%. Text stays solid at any value.
    • Blur — 0–20 px, default off.
    • Fit — Fill (the default) covers the grid and crops what does not fit; Fit shows all of it, on the terminal’s background color.
    • Speed — for a video or a GIF: from a quarter pace to double, default normal. On Windows a GIF follows it too; on macOS a GIF plays at its own pace and gets no Speed row.

    See Backgrounds for how one meets a theme.

  • Pane style — how terminals sit in the grid: Spaced (small gaps and rounded corners, the default) or Boxy (no gaps, square corners — the tiling-window-manager look). Borders stay in both, so two terminals never read as one.

  • Resize panes by dragging — default on. Off gives every pane an equal share and takes the handles away, which is the grid exactly as it was before the feature existed. Your proportions are remembered either way, so turning it back on returns the layout you had rather than a blank one. Opening or closing a pane resets them regardless of this setting — that rule belongs to resizing, not to the toggle.

  • Animate panes — default on. Panes glide into place when they swap, move or resize; a maximized pane grows from its cell to fill the grid and shrinks back when restored; a new pane settles into its cell and a closed one fades from its place; a stashed pane flies into the shelf’s count and back out. The sidebar slides in and out, and a workspace fades in once it has opened. Off, everything jumps straight to where it goes. Reduced motion in your system settings turns it off too.

  • Git diff view — side by side or stacked; the same setting as Diff layout under Git.

  • Default font size — 11 to 18 px, the base text size for every terminal. Zooming a single pane is an offset on top of it, so changing it here moves them all and keeps each pane’s own zoom. The font itself, the cursor style and cursor blink are under Terminal.

  • File icons — the icon set the file tree draws with: built-in (colored by type) or an installed pack. It previews as you browse the list. Manage icon packs → Marketplace & installed… opens the Marketplace’s icon packs.

  • Folders — Themes folder, Icons folder and Backgrounds folder open those directories. Drop a theme, an icon pack or a background in by hand and reopen Settings to see it.

The status bar is always visible. Its space stays reserved, so waiting notices and recovery controls do not resize the pane grid. Waiting-pane visibility is configured under Agents, below.

Terminal

  • Font — the list is the monospaced fonts actually installed on the machine; Custom… takes any other family by name. A chosen family sits in front of the shipped stack, so a missing glyph still renders monospaced.
  • Cursor style — block, bar or underline — and Cursor blink, on by default.
  • Modern Unicode widths — Unicode 11 width tables, so emoji and CJK measure two cells and the box art agent CLIs print stays aligned. Default on; turn it off only for an older program that assumes the legacy character widths.
  • Confirm multi-line pastes — Only when the lines would run (the default) asks before pasting several lines only when the receiving program would run them on arrival. Programs that take a paste as one block you still submit yourself — every modern shell and agent CLI — do not trigger it. Every multi-line paste always asks; Never never does. A single line never asks. This applies to keyboard and right-click paste alike.
  • Right-click in a terminal — Automatic (the default) opens a menu on macOS and copies or pastes elsewhere. Open a menu always shows Copy, Paste, Select all, Clear and Find. Copy the selection, else paste is the Windows console habit: with text selected a right-click copies it, with nothing selected it pastes.
  • Zoom controls (Ctrl+scroll) — whether Ctrl+scroll (⌘+scroll on macOS) over a pane resizes its text. Default on. The keyboard zoom keys work either way.
  • Follow terminal titles — pane headers show the title the running program reports (OSC 0/2) rather than the shell name. Default on. A title you set by hand always wins.
  • GPU terminal rendering — draws the terminal on the graphics card, so box art and block characters land exactly in their cells. Default on; the escape hatch if the renderer runs out of memory on a very long agent session. Applies to newly opened panes.
  • Scrollback lines — lines retained per terminal, 1,000 to 20,000, default 8,000. Memory scales with this times the number of open panes.

Browser

Settings for browser panes.

  • Search engine — where a browser pane’s URL bar sends anything that is not a web address: DuckDuckGo (the default), Google, Bing or Brave. Web addresses and localhost ports are never searched; they open directly.
  • New panes open — what Ctrl+Shift+B lands on. Takes anything the URL bar takes, so localhost:3000 puts every new pane on your dev server. Empty means a blank pane with the URL bar focused. A pane opened by a page — a link that wanted a new tab — keeps its own address, and so does a clone.
  • Browser button on the titlebar — default on: the globe in the title bar, right of the favorites star, that opens a browser pane in one click. Off takes the button away and puts a Browser row in the + button’s shell list in its place; the chord and the command palette open one either way.
  • Warn before the tenth browser pane — default on. Each browser pane is a native webview with its own renderer process, so ten live pages are a real memory and CPU load; opening a tenth onto the grid asks first, with Open anyway and Don’t warn again. Stashed panes are not counted. Off skips the ask.
  • Sound in new panes — default on. Off means new browser panes start muted; the speaker in each pane’s header unmutes that one page and stays visible while it is muted, so silence is never a mystery. Muting works on Windows, and on macOS where the system’s WebKit supports page audio control; where it does not, pressing the speaker says so instead.

SSH

Settings for SSH connections.

  • SSH connections — default off. On adds Connect via SSH… to the bottom of the + button’s shell list and lets the command palette’s Connect via SSH run; off, the palette still lists it but refuses, saying where to turn it on. SSH panes that already exist keep working either way — reconnecting, cloning and session restore do not ask. While it is off, this switch is all the category shows.
  • OpenSSH client — which installed client opens SSH panes. Automatic (the default) takes the first one found: on Windows the built-in Windows OpenSSH, then Git for Windows’s, then ssh on your PATH; on macOS the system ssh first. Every client found is listed with its version, and A path… takes any other ssh executable. The chosen client’s agent, keys and config are the ones in play — on Windows the two clients do not share them — and the line under the row names the client in use and the ssh_config file it reads.
  • Keep idle connections alive — how often a keep-alive crosses each idle connection: 0 to 120 seconds in steps of 15, default every 30. It keeps a NAT or a firewall from dropping a quiet connection without a word, and notices a dead one within a few probes instead of on your next keystroke. It reaches the client as ServerAliveInterval, ahead of your own ssh config — the one option TermHQ adds on its own. At 0 (off) it adds nothing and leaves your config in charge.

Passwords, passphrases and host-key questions are the client’s own, answered in the pane; TermHQ stores none of them. Saved profiles live in ssh-profiles.json beside config.json, with no secrets in them.

Editor

Settings for editor panes and language servers.

  • Word wrap — soft-wrap long lines instead of scrolling sideways. Default off.
  • Minimap — Monaco’s overview column. Default off: grid panes are narrow, and the minimap spends width the code wants.
  • Font size follows the terminal — default on, so one knob rules both. Turn it off and an Editor font size slider, 8 to 32 px, appears beside it. Per-pane zoom stacks on top of whichever is in effect.
  • Format on save — ask your language server to format the document every time you save. Default off, because a save that silently reformats a whole file is a diff nobody asked for. Formatting by hand works regardless.
  • Recover unsaved changes after a crash — default on. Mirrors unsaved text so a crash, force-quit or power cut does not take it. Turning it off deletes everything it had mirrored.
  • Files panel shows the repo while editing — default on: with an editor focused, the Files panel roots at the file’s repository and reveals the file in the tree. Off gives you the file’s own folder instead. Terminals are unaffected either way.
  • Editing shortcuts stay in the editor — default on: app chords that Monaco also binds fall through to the editor while one is focused. See Keyboard shortcuts. Expand Editor shortcut reference for a read-only list of the keys an editor pane answers to, grouped under Find, Multi-cursor, Lines, Navigate, Tabs, Format, Markdown, and Undo, save & close.
  • Language intelligence — the master switch for language servers. Expand Language server setup to add or enable a server, edit its command and arguments, watch live status, restart it, or read its log. Default on — but TermHQ ships no servers, so nothing runs until you install one. Arguments, Languages and Root markers keep spaces and commas while you type; press Enter or move to another field to apply the entry. See Adding your own server for the field formats.

Agents

The launchers lead the category, in a card that is always open:

  • Agent launchers — the list behind every pane header’s ✳ button and every “Open in <shell>” agent flyout. Each row shows the digit it answers to after Ctrl+Shift+A, the mark the menu shows for it, its name, whether its command was found, is not on PATH or is not verified, and the command itself, typed into the pane’s shell as written — flags welcome (claude --dangerously-skip-permissions). Ships with Claude Code, Codex, OpenCode, Antigravity, Grok Build, Gemini CLI, GitHub Copilot CLI and Cursor CLI, and an install that predates one of those picks it up once; one you remove stays removed. The refresh button beside Add agent looks for installed agents again. Add agent adds a row with the cursor in its name. Reorder by the grip — drag it, or focus it and use the arrow keys, Home and End — or with the up and down buttons, and removing one asks Remove? first. The order is both the menu’s order and the digits; an entry whose program is not on PATH is left out of the menu, and the next one takes its number.
  • IDE command — in the Open in IDE card: what the </> button runs against a directory. Default code; flags allowed. On macOS, command detection uses your login-shell path even when TermHQ opens from Finder or the Dock; see Running coding agents.

The Idle agents card holds the rest:

  • Agent idle badge — badge a pane that was busy while you were looking elsewhere and has since gone quiet. Default on.
  • Quiet seconds before badge — how long a busy pane must stay silent before it is marked for attention: 5 to 60 seconds, default 10; applies to both badges and waiting notices. Shown while Agent idle badge is on. Raise it for agents that pause to think; silence is not confirmation that a job succeeded.
  • Show waiting panes in the status bar — default on. While the window is focused, an agent or command that goes quiet while you are looking elsewhere appears in the waiting list. While the window is in the background, it sends a native OS notification as well, and the entry is still there when you come back. Off disables both, without changing Agent idle badge.
  • Always show it, even when nothing is waiting — default off. Appears while waiting notifications are enabled. On keeps a muted 0 waiting item in the bar when the list is empty; off hides it until a pane needs your attention.
  • Notification color — the color every attention surface draws from. Defaults to the active theme’s accent; a preset (amber, white, red, green, blue) or Custom… pins it across all themes.

The waiting list shows panes newest first, each with the time it has been waiting since — when it went quiet — and whether it is in the grid or in the stash shelf. Select one to return to the pane, or dismiss a notice with its × (or all of them with Dismiss all) without interrupting its work. Notices have no auto-dismiss timer. Fresh terminals do not raise waiting notices just for startup output. See When a pane needs your attention for the full behavior.

Git

The Source Control panel can review and stage changes, commit, browse history, manage branches, sync, resolve conflicts, use stashes, and create worktrees. These settings tune its defaults:

  • Worktree roots — folders containing repositories or worktrees that you want in the global Worktrees view. Type a path or use Choose folder…. With no roots set, nothing is scanned and the status-bar item stays hidden. Removing a root only stops tracking it; nothing on disk changes.

  • Branch order — how the branch picker sorts: most recently committed first, or alphabetical.

  • Pull style — what pull does when your branch and its upstream have both moved: fast-forward only (the default — it stops and says so rather than surprising you), rebase, or merge.

  • Auto-fetch — a quiet background fetch so ahead/behind counts stay honest: off by default, or every 5 to 60 minutes in 5-minute steps. Failures are silent on purpose; a fetch that fails on a plane should not raise a banner.

  • Prune on fetch — drop remote-tracking branches whose upstream is gone. Default on.

  • Refresh every — how often the panel re-reads status, 1 to 30 seconds, default 3; a very large repository may prefer a longer interval.

  • Conflict count on the Source Control tab — a badge on the tab itself, so a merge an agent started in a background pane is visible while you are looking at Files.

  • Counts beside the branch in the status bar — default on: changed files, commits to push and commits to pull, beside the branch name. Off leaves the branch alone; hovering it still gives the counts.

  • Diff layout — unified (stacked) or side by side; the same toggle lives in the diff window’s header, and under Appearance as Git diff view.

  • Committer pictures in History — default on. A picture beside each commit in History: a GitHub noreply address names its account, anything else asks Gravatar by email digest, cached after the first fetch. Off shows initials and sends nothing.

Voice

  • Voice dictation — show the mic button and honor the dictation chord. Default on — but the button only exists once a speech model is installed, so a fresh install shows no voice controls at all until you download one.
  • Microphone — which input to record from; System default unless you pick one, and the system default takes over if the chosen one is unplugged.
  • Dictation language — English by default, fifteen more (Arabic, Chinese, Dutch, French, German, Hindi, Italian, Japanese, Korean, Polish, Portuguese, Russian, Spanish, Turkish and Ukrainian), or Auto-detect, which lets a multilingual model identify the language per recording. English-only models transcribe English regardless, and the panel warns about that combination when you pick it.
  • Test microphone — record a few seconds and play them back through the exact capture path dictation uses, with a verdict on the level — so “is my mic working?” gets answered before any words are spent on it.
  • Speech model — the model manager: download with live progress and cancel, switch between downloaded models, delete them, or import your own file. Every row shows its size and language coverage, every downloaded model records where it came from and when, and the panel links its sources so you can verify them yourself.
  • Hold to talk — default off. Hold the key below in a terminal for a moment to start dictating; let go to transcribe. A tap still types what the key normally types. Off by default because on Space it takes the hold away from the programs in the terminal, Claude Code’s own hold-to-dictate included.
  • Hold key — Space by default. Click it and press any single key, a modifier such as Right Ctrl included; Esc keeps the current one. On a key of its own, Claude Code’s hold-to-dictate keeps working alongside. See Dictation.

Files

  • Show hidden files (dotfiles, OS-hidden) — default on; ls -a is the terminal user’s default worldview, so hiding is the opt-in.

  • Open with… — the right-click “open with” list. Each entry is a name plus a command, run either as an app, detached (Notepad on Windows, TextEdit on macOS), or in a new terminal pane opened in the file’s directory (vim, nano). Add opener adds one; reorder and remove them the way you do favorites.

    A folder’s menu starts with New file… and New folder…, which create inside that folder, and every file and folder menu ends with Rename… and Delete… (F2 and Delete on a focused row do the same). Rename edits the name in place with the name preselected and the extension kept; Delete asks first and moves the item to the Recycle Bin or Trash, never deleting outright. The panel’s root and the folders above it offer neither. Two more entries appear on their own rather than from this list: Open in IDE, and Open in Obsidian for a folder that is actually a vault on a machine that actually has Obsidian. A folder counts as a vault once it contains the .obsidian directory Obsidian writes the first time it opens one. It opens through Obsidian’s own URL scheme rather than its executable, so a vault already open is brought to the front instead of opened twice.

  • Terminal openers run in — which shell those terminal openers get. Until you pick one they stay hidden entirely, because vim in PowerShell helps nobody.

Whether the sidebar shows, and its side and width, are under General. The sidebar header identifies the pane or folder it is following, and its right edge holds a small toolbar. On both tabs, Pin stops the sidebar following the focused pane — Files stays on its folder, Source Control on that folder’s repository, and the header reads Pinned until you unpin. On the Files tab it adds New file and New folder (a name row appears in the tree; Enter creates, Escape cancels, and a new file opens straight into the editor), Find files by name (the same search Ctrl+F runs after you click in the panel), Collapse all, Refresh (the icon turns once and the button stays disabled until the re-read has finished), and, when the folder is an Obsidian vault on a machine that has Obsidian, a button carrying Obsidian’s mark that opens the vault. With no terminal to follow, the panel says No folder open and offers Open folder…. The path bar above the tree stays on one line: a deep path folds its middle folders into a … button whose menu lists them, and each still opens on click or offers a terminal on right-click.

Shortcuts

Every action, rebindable, grouped under six headings: Open panes, Source Control, Terminals, Focus & layout, Arrange without the mode and App. Only your overrides are stored — see Keyboard shortcuts. Once any differ from the defaults, Reset all shortcuts puts them all back, after asking.

  • Show shortcuts on screen — default off. Shows each chord you press along with what the app did with it, for demos, screen recordings, and working out why a chord seems to do nothing.

Keyboard shortcuts

https://termhq.dev/docs/keyboard-shortcuts/

Every default shortcut in TermHQ, how to rebind them, and how conflicts with terminal programs are resolved.

On macOS, ⌘ replaces Ctrl in every shortcut below — with one deliberate exception, dictation, which is Ctrl+Alt+Space on both. On macOS Ctrl belongs to the shell: Ctrl+F and Ctrl+B are readline’s forward-char and backward-char, so binding them app-side would swallow keys the terminal is supposed to receive.

Most of the app-level chords are three keys rather than two. That is not padding: the single-Ctrl versions nearly all belong to the shell — Ctrl+C is the interrupt, Ctrl+D is EOF, Ctrl+S freezes output, Ctrl+L clears the screen — and no Ctrl+Shift+letter is a distinct control code.

Terminals and panes

Action Shortcut
New terminal (default shell) Ctrl+J
Duplicate focused pane Ctrl+Shift+J
New browser pane Ctrl+Shift+B
New editor pane Ctrl+Shift+E
Connect via SSH unassigned by default
Delete focused terminal Ctrl+Shift+D
Restore last closed terminal Ctrl+Shift+R
Show recently closed panes unassigned by default
Rename the focused pane unassigned by default
Find (terminal or files) Ctrl+F

Ctrl+J and Ctrl+Shift+J pair on purpose: J opens a terminal, Shift+J opens one like this one. B is for browser and E for editor, with Shift keeping them separate from other actions. On Windows, for example, plain Ctrl+B toggles the sidebar, but Vim also uses it to page backward in normal mode.

Connect via SSH opens the SSH picker once SSH is turned on in Settings → SSH → SSH connections — see SSH connections. Show recently closed panes opens the status bar’s list of panes still inside their undo window, with the keyboard on its first row. Rename the focused pane opens the pane’s name for editing; an empty name brings back the automatic one. Find follows where you are: over a terminal it opens that pane’s find bar, and when you were last in the Files panel it searches file and folder names.

On macOS, ⌘+W closes what it points at: the tab in a focused editor, otherwise the focused pane — through the same close as Delete focused terminal, so a closed terminal can still come back with Undo close. Only when no pane is left on the grid does it close the window.

Layout

Action Shortcut
Focus pane left / right Ctrl+Shift+← / →
Focus pane up / down Ctrl+Shift+↑ / ↓
Jump to the newest waiting pane Ctrl+Shift+N
Focus the previous pane unassigned by default
Arrange pane (mode) Ctrl+Shift+G
Push pane left / right / up / down unassigned by default
Maximize focused pane (toggle) Ctrl+Shift+Z
Switch between Grid and Columns unassigned by default
Reset pane sizes unassigned by default
Stash focused pane Ctrl+Shift+S
Show/hide the stash shelf Ctrl+Shift+O
Restore all stashed panes unassigned by default
Close all stashed panes unassigned by default
Ultra focus mode (toggle) Ctrl+Shift+U

Focus movement is geometric — it steps to the nearest pane in that direction, preferring one that shares an edge, so focus follows what your eye sees rather than the order panes were opened. In Columns layout only left and right apply.

Jump to the newest waiting pane goes to the pane that most recently went quiet while you were looking elsewhere — the first entry in the status bar’s waiting list — bringing it back from the shelf, or out from behind a maximized pane, if it has to. See When a pane needs your attention. Focus the previous pane is the way back after a jump: it returns to the pane that had focus before this one.

Maximize focused pane fills the grid with one pane, and the same chord restores the grid; a double-click on a pane’s header does the same. Switch between Grid and Columns flips the layout and keeps the panes in the order you read them, Reset pane sizes puts every dragged row and column back to an even share, and Restore all stashed panes and Close all stashed panes act on the whole shelf — restoring asks first when it would leave every pane very small, and closing always asks.

Navigation

Action Shortcut
Command palette Ctrl+Shift+P
Settings (focus search) Ctrl+P
Workspaces Ctrl+Shift+W
Toggle sidebar Ctrl+B
Worktrees Ctrl+Shift+T
Run an agent by number Ctrl+Shift+A, then 1…9/0
Open a favorite by number Ctrl+Shift+L, then 1…9/0

The split between the two P chords follows VS Code’s: Ctrl+Shift+P is the palette of every action by name, Ctrl+P is quick-open — here, Settings with the search box already focused, so you type the setting you want instead of hunting categories. Both toggle: the same chord again closes what it opened.

The palette opens more than actions. Beside them it lists your favorites, your shells, the agents it found (Run and the agent’s name), your other workspaces, themes and every Settings page — and your saved and recent SSH connections while SSH is on. With nothing typed they sit under headings, with what you ran last first.

The two numbered pickers are deliberately two strokes rather than ten chords, which keeps the digits free the rest of the time. While one is armed, a card lists the numbered entries so the mapping is never guesswork; the agent card’s title names the terminal the command will be typed into. Both the number row and numeric keypad work in the agent and favorite pickers, including 0 for the tenth entry. Esc cancels, and any other key cancels and then does what it normally does.

The global Worktrees view is also available from the command palette and its status-bar item.

The Git actions have no default shortcut: Git: Open the Git panel, Git: Open History, Git: View File History, Git: Commit, Git: Stage All Changes, Git: Unstage All Changes, Git: Fetch, Git: Pull, Git: Push, Git: Switch Branch, Git: Stash Changes and Git: Refresh. Run them from the command palette, or give the ones you use a chord under the Source Control heading in Settings → Shortcuts. See Source Control.

In a pane

Action Key
Open a web link in a terminal’s output, in your default browser Ctrl+click
Open it in a browser pane beside the terminal instead Ctrl+Shift+click
Find bar: next / previous match Enter / Shift+Enter
Find bar: match case, whole word, regular expression Alt+C, Alt+W, Alt+R
Close the find bar Esc
Maximize the pane, or restore the grid Double-click its header
Rename the pane Right-click its header, or F2 with the keyboard on the header’s buttons

A plain click on a link only focuses the pane or starts a selection; hover one and a hint says how to open it. On macOS the find bar’s toggles are Option+C, W and R. Ctrl+F on a pane whose find bar is already open puts the keyboard back in it.

On a terminal, a right-click on the header opens the pane’s menu instead — Rename…, Copy path, Reveal in File Explorer (Finder on macOS), the header’s buttons by name, and Close. F2 never renames from inside the terminal itself, where it belongs to the program.

In the Files panel

With a row focused (click one, or Tab into the tree):

Action Key
Open a file, or expand / collapse a folder Enter or Space
Walk the tree ↑ ↓, Home End
Expand a folder, or step into one that is open →
Collapse a folder, or go to the parent folder’s row ←
Jump to a name Type its first letters
Go up a folder Backspace
Open the row’s menu Shift+F10 or the menu key
Rename F2
Delete (asks first; moves to the Recycle Bin / Trash) Delete

Inside a row’s menu, a shell row (“Open in PowerShell” and the like) opens its agent flyout with →, a right-click or the chevron at its edge, and ← or Esc closes it.

In menus

Every menu takes the keyboard the same way: ↑ ↓, Home and End move between rows, Enter picks one, Esc closes the menu, and a letter jumps to the next row that starts with it — press it again for the one after.

Zoom

Action Shortcut
Zoom pane in / out Ctrl+= / Ctrl+-
Reset pane zoom Ctrl+0
Zoom the pane under the pointer Ctrl+wheel, or a trackpad pinch

This is text size in one pane, not that pane’s share of the grid — for the latter, see Maximize above. After each step a terminal pane shows its new size for a moment, with the chord that resets it: 15 px · Ctrl+0 resets. Settings → Terminal → Zoom controls turns the wheel and the pinch off; the keys keep working.

Editing

Action Shortcut
Copy selection Ctrl+Shift+C
Copy Ctrl+C (with a selection)
Interrupt Ctrl+C (with no selection)
Paste Ctrl+V, Ctrl+Shift+V, or Shift+Insert

Voice

Action Shortcut
Voice dictation (start / stop) Ctrl+Alt+Space
Hold to talk (opt in) hold Space, or the key you set

The one chord that does not move to ⌘ on macOS: ⌘+Alt+Space is Finder’s search window, while Ctrl+Alt+Space collides with nothing a shell wants. It dictates into the focused terminal, or into the text field you are typing in.

Hold to talk is a hold, not a chord, so it lives in Settings → Voice rather than here: turn it on there and set its key by pressing it — any single key, Right Ctrl included. See Dictation.

Why Ctrl+C does two things

In a terminal, Ctrl+C means “interrupt”, and that meaning cannot be given away — it is how you stop a runaway process. But when text is selected, “interrupt” is almost never what you meant.

So TermHQ copies when there is a selection and interrupts when there is not. This is what Windows Terminal does, and it is safe because copying clears the selection: a Ctrl+C that copies when you meant to interrupt costs one extra keypress and never more, because the next one finds nothing selected.

Ctrl+Shift+C is the unconditional copy, and the one you can rebind. The plain-Ctrl rule is off on macOS, where ⌘+C already copies, and off in ultra focus.

Rebinding

Settings → Shortcuts lists every action with its current chord, under six headings — Open panes, Source Control, Terminals, Focus & layout, Arrange without the mode, App — so you find one by what it does rather than by scanning all of them. Search filters across every group.

Click a row and press the combination you want. To leave an action with no shortcut at all, use the slashed-key button that appears beside the chord while you are recording — Backspace does the same thing, but only if you already knew that, and while recording every other key means “use this one”. Only your overrides are stored — anything you have not touched follows the default, so defaults can improve between versions without overwriting your choices.

Recording stops if you leave the list — switching category, typing in the search box, or closing Settings — so a recording you walked away from can never land on a row you are no longer looking at.

A chord can belong to exactly one action, so taking an occupied one asks first: a confirm card names the action that currently holds it and says it will be left unassigned. Per-row reset works the same way in reverse — if that action’s default has since been given to something else, resetting tells you whose chord it is taking back. Once anything differs from the defaults, the section ends with a count and a Reset all shortcuts button.

An action you have unassigned is still listed in the command palette and still runnable from it, so dropping a chord never costs you the command.

The palette also says when an action cannot do anything right now and why — only one pane in the grid beside Arrange pane, voice is off in Settings beside Voice dictation, the focused pane is an editor, not a terminal beside the ones that need a shell. Those rows are dimmed but still listed and still runnable, because the palette is how you find an action in the first place, and hiding one teaches you nothing about what it needs.

A chord gets the same treatment. When its action has nothing to do right now, TermHQ does not swallow the key: it goes on to the focused pane, where it may mean something to the program running there.

Three actions want a terminal

Running an agent by number and voice dictation type into a shell, and Copy selection copies a terminal’s selection, so all three want a terminal focused rather than just any pane. The first two also need that terminal’s shell to be running — a terminal whose shell has ended refuses them — and the agent picker refuses an SSH pane as well, because the agents it offers are the ones found on this machine and the command would run on the far host.

Dictation can also start in one of TermHQ’s own text fields — the commit box, a search box, a browser pane’s address bar — and types there. See Dictation.

With an editor or a browser pane in front, all three refuse: the palette says which kind of pane is in the way, and the chord goes on to the pane rather than doing something that could not work.

You are not left without a way to copy: an editor and a browser each handle Ctrl+C themselves.

Seeing what a key did

Settings → Shortcuts → Show shortcuts on screen (off by default) puts a card on screen for each chord you press, saying what the app did with it: ran an action, nothing bound, the editor kept it (or it was the editor’s own key), ultra focus passed it through, the action could not run — with the reason the palette would give — or a text field kept it (typing — … not run).

It is there for demos and screen recordings, and for the moment a chord seems to do nothing and you want to know which of those it was. Only keys held with Ctrl, Alt or ⌘ and the function keys are ever shown — it cannot display your typing.

What is not rebindable

A few behaviors answer to terminal state or to the mouse rather than to a chord, so they are not keymap entries: paste (Ctrl+V / Ctrl+Shift+V / Shift+Insert), right-click, and Ctrl+scroll zoom.

The two mouse behaviors have settings of their own instead. Settings → Terminal → Right-click in a terminal chooses between a menu — Copy, Paste, Select all, Clear and Find — and copying the selection, or pasting when there is none; Automatic, the default, is the menu on macOS and copy-or-paste on Windows. Settings → Terminal → Zoom controls turns Ctrl+scroll zoom off.

Bare arrow keys cannot be keymap entries either — they would break every TUI — so TermHQ uses them only where you have gone on purpose: arrange mode, the stash shelf, a gutter between panes that you have tabbed to (the arrows move it, Enter evens it up), the status bar’s lists of closed and waiting panes, and menus. None of them is a standing binding.

Four defaults that take a key from your shell

Most of TermHQ’s shortcuts are chosen so the shell loses nothing. Four are not, and it is better that you hear it here than discover it:

Chord What it takes on Windows
Ctrl+B (sidebar) Page-backward in Vim’s normal mode; cursor-backward in shell line editing.
Ctrl+P (settings) Previous-command history, for anyone who walks history with it instead of ↑.
Ctrl+F (find) Page-forward in Vim’s normal mode and less; cursor-forward in shell line editing.
Ctrl+J (new terminal) Newline — to a shell, Ctrl+J is Enter.

Ctrl+Shift+←/→ also costs PowerShell its word-selection. That one was a deliberate trade: pane navigation that works in every shell, against one editing convenience in one shell.

None of this applies on macOS. There every shortcut hangs off ⌘, which never reaches the terminal at all, so there is nothing to collide.

Any of them can be rebound or cleared in Settings → Shortcuts, per machine.

When a text field or a dialog has focus

TermHQ’s own text fields — a browser pane’s address bar, the commit box, a search box, a pane’s name while you rename it — and anything under an open dialog get their keys first. There only the launchers run: the command palette, Settings, Workspaces, Connect via SSH, Worktrees, and voice dictation, which types into the field you are in. Every other chord is left to the field or the dialog, so Ctrl+Shift+Z in the commit box does not maximize the pane behind it, and Ctrl+Shift+← / → select by word as they do in any text box.

A terminal’s input and an editor’s are not text fields in this sense. They keep their keys by the rules on the rest of this page.

When an editor pane has focus

An editor pane binds keys of its own, and they are bound in the pane so your shell loses nothing: Ctrl+S still freezes a terminal’s output and Ctrl+W still deletes a word everywhere else. The full set is on the editor page.

Three app chords also step aside for the editor, because the editor binds them to something you are more likely to want while typing:

Chord The editor uses it for
Ctrl+F Its own find widget, instead of terminal scrollback search
Ctrl+Shift+L Select all occurrences, instead of the favorites picker
Ctrl+Shift+T Reopen the last closed tab, instead of opening Worktrees

On macOS, ⌘+Shift+Z joins them — there it is the standard redo, so redo wins over Maximize. On Windows redo also has Ctrl+Y, so Maximize keeps its chord.

The pane-focus chords stay in the editor too: there Ctrl+Shift+arrow selects text, as it does in any text box.

Settings → Editor → Editing shortcuts stay in the editor turns the yielding off and runs the app action everywhere, pane focus included. Ultra focus hands over every key regardless.

When a browser pane has focus

A browser pane is a real web page, and a web page wants keys too. On Windows and macOS, TermHQ’s chords are taken before the page sees them, so pane focus, arrange mode, stash, close, maximize and the pickers all work with a page focused exactly as they do with a terminal focused. Afterwards the keyboard goes where the result needs it — back into the page, or into the app for arrange mode’s arrows and a picker’s digits.

A short list is deliberately left to the page:

Chord Who gets it Why
Ctrl+F The page Its own find bar is the one you meant
Ctrl+= / - / 0 The page The browser engine’s own zoom
Copy The page Same
Ctrl+Shift+A The page It would type into a terminal that is not there
Ctrl+Alt+Space The page Same — dictation needs somewhere to write

On macOS the first two rows are the pane’s instead. The page’s engine shows no find bar of its own there, so ⌘+F opens the pane’s find bar, and ⌘+= / - / 0 still zoom the page, with TermHQ doing the zooming. macOS also gives a focused page the usual browser keys, unless your keymap has claimed them: ⌘+L for the address bar, ⌘+[ and ⌘+] for back and forward, ⌘+R to reload.

The address bar is one of TermHQ’s own text fields, so while you type an address only the launchers run — see When a text field or a dialog has focus.

Ultra focus (Ctrl+Shift+U) hands a browser pane every key except its own toggle, the same bargain it makes with a terminal.

When a terminal program wants the same key

Terminal programs such as Vim have their own shortcuts, and some collide with TermHQ’s. For example, on Windows, Ctrl+B opens the sidebar instead of paging backward in Vim’s normal mode.

Two ways out:

  1. Rebind or clear the TermHQ action in Settings → Shortcuts.
  2. Ultra focus (Ctrl+Shift+U) — hands every keystroke to the terminal and turns TermHQ’s shortcuts off. That includes Ctrl+V, which normally pastes, so Vim can receive it to enter visual block mode.

Two things stay TermHQ’s by design even in ultra focus: Ctrl+Shift+V still pastes — it is not a control code, so no TUI can want it — and mouse behaviors are unaffected, so right-click and Ctrl+scroll zoom keep working. Its own chord stays live too, because a mode with no keyboard exit is a trap; a badge appears in the title bar and can be clicked to leave, and the focused pane’s edge breathes in the attention color while the mode is on.

Ultra focus is deliberately not remembered across restarts. A mode that outlives a launch is a mode you can be stuck in without knowing why.

Theming

https://termhq.dev/docs/theming/

Built-in themes, writing your own, theming the workbench and editor, splitting the terminal palette, and importing themes from Open VSX.

TermHQ ships with ten built-in themes and will use any valid theme file you add.

Dark: Default, Void, Pitch (pure black, for OLED), Graphite, Abyss, Aurora, Ember, Moss. Light: Paper (true white) and Dawn (warm cream).

Default uses neutral black, gray and white with a restrained glass-inspired finish. The controls, spacing options and interactions are shared across all themes; choosing a downloaded theme keeps that theme’s palette. The default look does not recolor themes you already installed.

Focused panes have a restrained, theme-colored glow around their outer edge. The pane header keeps its normal divider, so focus is marked on the frame rather than by an extra line inside it. This applies to downloaded themes too. Boxy panes keep the cue inside their edge; increased-contrast settings remove the halo. To make the focused pane stand out further in any theme, turn on Settings → Appearance → Dim unfocused panes, which washes the others toward the theme’s background.

A few themes make their accent transparent. TermHQ then stands the theme’s own focus, link or text color — the first of them that is visible — in for the accent everywhere it paints: focus rings, primary buttons, the focused pane’s mark, unsaved-tab markers, the branch name and progress bars. The theme’s file is not rewritten; the stand-in lasts only while that theme is applied.

Choosing one

Settings → Appearance → Theme. Type to filter the list, then arrow or hover through it to preview. The app repaints behind the dropdown — chrome, terminal palette, editor and all — with the option you started on badged current. Enter or a click keeps that one; Esc or a click elsewhere puts back where you were. Nothing is written to disk until you keep something, so looking at thirty themes costs zero saves. A theme you keep applies to every open window at once.

The terminal palette can differ from the interface

A theme has two halves, and they can be driven by different themes.

Settings → Appearance → Terminal theme picks any theme as the source of the terminal palette while the chrome stays on another — Graphite chrome hosting a Dracula terminal is a preference, not a fork. Leave it on Match app theme and the terminal follows the app theme.

For hand-made and built-in themes, that terminal palette also supplies the editor’s syntax colors. Choosing a separate terminal theme therefore gives the terminals and editor the same visual language while leaving the surrounding workbench alone.

Worth knowing if you author a theme whose two halves only look right together: your terminal block may end up in use under somebody else’s ui block.

Backgrounds

Settings → Appearance → Background puts a picture, a GIF or a looping video behind your terminals, and it works with every theme, light or dark. The background lies on the terminal palette’s own background color, drawn at the Transparency you set, and the terminals let it through. So terminal.background becomes the base color under the picture, and a picture set to Fit that does not fill the grid sits on that color.

The rest of the theme draws as usual. Pane headers stay solid, so names, tools and the focused pane’s edge read as before, and editor panes and web pages keep their own surfaces. Terminal text renders slightly softer while a background is set, because the terminal then draws on a see-through surface; pick None and full sharpness returns.

A background belongs to the whole app, like the theme: one for every workspace, and a change reaches every open window at once. Files over 1 GB are refused. Blur, Fit and playback speed are covered under Configuration.

Writing your own

Themes are JSON files in the themes/ directory inside your configuration folder (Configuration). Drop one in, reopen Settings, and pick it. Settings → Appearance → Folders → Themes folder opens that directory.

A theme has a name and those two sections:

{
  "name": "My Theme",
  "ui": {
    "bg": "#09090b",
    "panel": "#0b0b0e",
    "hairline": "rgba(255,255,255,0.08)",
    "hairlineStrong": "rgba(255,255,255,0.14)",
    "ink": "#fafafa",
    "muted": "#8a8a93",
    "faint": "#7d7d86",
    "accent": "#7c8cf8",
    "rec": "#ff5c5c",
    "attn": "#e8b34c",
    "selection": "#7c8cf84d"
  },
  "terminal": {
    "background": "#0b0b0e",
    "foreground": "#d6d6dc",
    "cursor": "#7c8cf8",
    "selectionBackground": "#3a3f6e80",
    "black": "#1a1a1f", "red": "#ff6b6b",
    "green": "#6bd68a", "yellow": "#e8c56b",
    "blue": "#7c8cf8", "magenta": "#c98bf0",
    "cyan": "#6bd6d6", "white": "#d6d6dc",
    "brightBlack": "#5a5a63", "brightRed": "#ff8a8a",
    "brightGreen": "#8ae5a5", "brightYellow": "#f2d98a",
    "brightBlue": "#9aa6fa", "brightMagenta": "#dba6f5",
    "brightCyan": "#8ae5e5", "brightWhite": "#fafafa"
  }
}
  • ui colors the application around the terminals. The base colors above are enough for a complete theme: TermHQ derives every surface you leave out. A theme can optionally take individual control of the title bar, status bar, sidebar, pane headers, popups, menus, inputs, buttons, selections, focus rings, links, warnings, success states, and Git file colors. The commented template names every option.
  • terminal colors the terminals themselves: the sixteen ANSI colors plus background, foreground, cursor and selection.

A few things you do not have to theme:

  • Workbench surfaces are derived from the base colors until you override them. A small theme still paints the whole application, including light themes, without needing dozens of entries.
  • ui.selection colors selected text in the chrome — inputs, file names, settings copy. Omit it and it falls back to accent at 30%. The terminal’s own selection is the separate terminal.selectionBackground, because the terminal draws that one itself.
  • ui.attn is the attention color for agent-idle badges and the waiting dock. Omit it and attention surfaces follow accent. A color chosen in Settings → Agents → Notification color overrides it, so a theme cannot count on winning that one.
  • ui.gitIgnored colors only the name of a Git-ignored file or folder in the Files tree. Its icon keeps its color and the row is never dimmed. Omit it and the name follows faint.
  • terminal.background also paints the padding ring between the rows and the pane frame, so a theme whose terminal differs from panel still reads as one surface rather than a black frame.

accent marks the active parts of the interface. When a theme supplies more specific colors, focus rings, buttons, selected rows, links, and Git states use those instead of forcing the accent into every role. panel should sit slightly above bg in lightness; the hairlines are the borders everywhere.

TermHQ keeps text readable whatever a palette says. muted, faint, link, warn, ok and the Git added, modified and deleted colors are raised toward ink until they reach a 4.5:1 contrast on the theme’s own surfaces. The accent gets the same floor wherever it is read as text — a branch name, a selected tab — while buttons and other fills keep its exact color. The built-in themes already clear the floor; it matters most for imported light themes. The example’s faint is chosen to clear it, which is why it reads #7d7d86.

The template is the contract

TermHQ writes _template.jsonc into your themes folder and keeps it current on every launch. It is a fully commented copy of every themeable key, so “Themes folder” always lands you next to working documentation.

It never loads as a theme itself: the loader skips .jsonc files and anything whose name starts with _. That prefix is also how you park a theme you do not want listed.

Themes you add yourself are listed under Custom themes in the Marketplace’s Installed view, where Remove deletes one. Built-in themes are compiled into the app and have no file to remove.

The editor follows the theme

Editor panes, diff views, and rendered Markdown now change with the active theme — background, gutter, cursor, selections, widgets, diffs, and syntax. A light workbench gets a light editor rather than dark syntax on a pale surface.

Built-in and hand-made themes derive syntax from the active terminal palette, so the editor and the terminals beside it feel like one environment. Themes imported from Open VSX keep the extension’s own editor colors and syntax rules.

If you are authoring a theme and want exact control, _template.jsonc includes an optional editor section. Most themes do not need it.

Importing VS Code themes

Settings → Appearance → Manage themes → Marketplace & installed… opens the Marketplace, a page inside Settings for Open VSX, a vendor-neutral extension registry. Its Themes tab has a most-downloaded shelf by default, live search, infinite scroll, and an Installed view of everything you already have. Back or Esc returns to Appearance.

Packs and variants

One extension can contain several color themes, such as light, dark and softer contrast variants. TermHQ keeps that relationship visible:

  1. In Browse, choose See variants to inspect what a pack includes.
  2. Install pack downloads its variants without changing your current theme.
  3. In Installed, expand the pack and choose Apply beside the variant you want. Applying an installed variant does not download it again. The variant the app uses reads In use, and the one your terminals use says Used by terminal; the pack’s own line says App theme in use or Terminal theme in use.

Search the Installed view by pack, variant or publisher to narrow the list. You can remove a single variant or choose Remove pack to delete all of its installed variants. The confirmation names everything affected, even when your search shows only one match. Update pack checks for a newer release first and says so when the pack is already up to date. Updating a pack can bring back a variant you removed.

How imported colors are used

TermHQ converts each VS Code color theme in the pack into its own format: the terminal palette, the colors for the full workbench, and the extension’s editor colors and syntax rules. The result is written into your themes folder and marked with where it came from.

Conversion fills in what real-world themes leave out, so secondary text remains readable, panes stay distinct, buttons keep enough contrast, and focus never disappears into the background. Comments in the source and themes that inherit from another file inside the same extension are both handled.

An imported file keeps the extension’s original colors in its vscode block, so it benefits when TermHQ’s converter improves: the next time themes are listed, an older import is re-derived from them automatically. That also means a hand edit to an imported file’s ui or terminal block is replaced when the converter next improves. To freeze a file exactly as you edited it, delete that vscode block, which holds the extension’s original color table and syntax rules, and the converter leaves the file alone from then on. The editor then takes its colors and syntax from the file’s ui and terminal blocks, as it does for a hand-made theme. Imports from before the source was saved have no such block; Update pack in the Installed view re-imports them.

Open VSX only. TermHQ does not use the Visual Studio Marketplace, whose terms of use restrict it to Microsoft products. Open VSX exists precisely so non-Microsoft tools have a legitimate source. Every download is one you chose; TermHQ redistributes nothing.

File icons

File icon themes use the VS Code icon-theme format and install the same way, from Settings → Appearance → Manage icon packs → Marketplace & installed…, the Marketplace’s Icon packs tab — Material, Catppuccin and vscode-icons among them, each under its publisher’s license. Settings → Appearance → File icons picks the active one, and it previews as you browse just like the theme list does.

Manual installs work too: drop a VS Code-format icon theme folder into the icons/ directory and reopen Settings. SVG only. Icon themes affect the file panel, not the terminals.

Under the hood

https://termhq.dev/docs/under-the-hood/

What TermHQ is built from: a native Rust core, the OS webview instead of a bundled browser — for the interface and for browser panes alike — and first-party parts everywhere it counts.

TermHQ is a Rust application. The parts that touch your system — spawning shells and their PTYs, keeping sessions alive after the window closes, reading and writing files — are native Rust code. Where a proven tool already does a job, TermHQ drives that tool instead of rewriting it: git runs through the git program installed on your machine, dictation through the whisper.cpp engine bundled with TermHQ, and SSH through the OpenSSH client already on your machine.

The interface is rendered by your operating system’s own webview through Tauri, not by a bundled browser. That one choice is why the installer is measured in megabytes rather than hundreds of them, why there is no runtime to install first, and why memory goes to your shells instead of to a second copy of Chromium. The interface itself is React, with the terminals rendered by xterm.js — the same emulator VS Code trusts — with GPU rendering and modern Unicode widths on top.

Two processes

TermHQ runs as two pieces: the window you see, and a small headless Rust process that owns every shell. The window can close or reload; the shells keep running, and the next window picks them back up. That is the whole mechanism behind persistent sessions — the terminal multiplexer is built in, so there is no tmux to learn.

The same background process owns SSH connections. An SSH pane is the OpenSSH client running under it like any shell, so closing the window does not drop the connection; it stays open for as long as the network holds.

Installing an application update restarts the shells and stops running commands and agents. Your workspace arrangement returns after the update. See Updating.

The editor is Monaco

Editor panes are built on Monaco, a mature code-editing engine, so multi-cursor editing, find and replace, and line moves work the way a full editor’s do rather than as an approximation. It loads only the first time you open an editor pane or a diff — in Source Control or its History — so a session that does neither never pays for it.

Language intelligence is a separate layer, and a strictly opt-in one: language servers are programs you install, launched on demand and shut down when the files that needed them close. TermHQ bundles none, at any version, ever.

Browser panes are the real engine

The same choice that keeps the installer small pays again for browser panes: a browser pane is your operating system’s browser engine embedded in the window as a child surface, positioned at the pane’s rectangle. The page is composited by the engine on the GPU. No frame is ever streamed through the application, and no keystroke or mouse move is ever synthesized — which is the difference between a web page and a screenshot of one that lags.

Because the page is arbitrary remote content, it is given no authority: browser surfaces hold none of the application’s permissions, remote pages are refused any channel into TermHQ, and navigation is fenced to http, https and about: pages.

One folder the interface can load from

The interface does not read your disk on its own; files reach it through TermHQ’s Rust side. Backgrounds are the one exception: to show a picture or play a video behind your terminals, the webview loads it straight from disk — but only from the backgrounds/ folder in your configuration directory, the one folder that route can reach. Nothing else on disk can be loaded that way.

Built from scratch

Most GUI terminals are assembled from the same off-the-shelf parts — a ready-made terminal widget, a layout library, tmux underneath for persistence. TermHQ’s core is built from scratch instead: the session engine, the tiling grid and its gravity, the workspace model, the theming system, the keymap, and Source Control.

Where a piece of the stack is the acknowledged best tool, TermHQ uses it and says so: terminals are drawn by xterm.js and files edited in Monaco, the two engines VS Code itself uses; dictation runs on whisper.cpp, entirely on your machine; git operations run through the git already on your PATH, with your credentials, hooks, and configuration; SSH connections run through the OpenSSH client already on your machine, with your keys, agent and ssh_config, nothing installed on either side and no secret stored by TermHQ; language intelligence comes from LSP servers you install yourself; themes and icon packs install from Open VSX.

What reaches the network

With local Whisper models, dictation is processed on your machine; downloads — a theme, an icon pack, a speech model — happen when you ask for them, from sources the interface names. Three things reach the network without a separate request, and each has a switch:

  • The update check runs shortly after launch and every six hours. Settings → General → Updates turns it off.
  • A startup report. Each time the app starts, it sends one request to api.termhq.dev saying it started, on which operating system (windows, macos or linux), and which version of TermHQ it is, such as 0.2.9. That is the whole report. There is no account, device or installation ID, and no hardware details, performance numbers, terminal content or workspace data. It is sent once per start, never retried, and only over a verified HTTPS connection. Settings → General → Privacy → Send startup reports turns it off. Turning it off sends nothing, cancels a report still on its way, and holds for every later start. It does not delete reports already received.
  • Committer pictures in Source Control’s History, on by default: a GitHub noreply address asks GitHub for that account’s picture, any other address goes to Gravatar only as a SHA-256 hash, and each picture is cached after its first fetch. Settings → Git → Committer pictures in History turns them off, and then nothing is sent.

Troubleshooting

https://termhq.dev/docs/troubleshooting/

Fixes for the problems people actually hit: monochrome agents, missing shells, stale sessions, language servers, unsaved edits, browser panes, and where the logs are.

An agent or CLI renders without color

Almost always an inherited NO_COLOR from whatever launched TermHQ. TermHQ scrubs the variables it knows about on every shell it starts, so if color is still missing, check your shell profile — a NO_COLOR, TERM=dumb or CLICOLOR=0 set there is applied after TermHQ hands the shell over, and TermHQ cannot override your own configuration.

Confirm with:

echo "TERM=$TERM NO_COLOR=$NO_COLOR COLORTERM=$COLORTERM"

An installed agent is missing from the menu

Open Settings → Agents and read what its row says:

  • not on PATH — TermHQ can’t find the program. Press the refresh button beside Add agent to look again. If it’s still missing, check that your terminal finds it (where gemini on Windows, which gemini elsewhere), or put the program’s full path in the launcher’s command. On macOS, restart TermHQ after changing your shell’s PATH.
  • not verified — a program with that name exists, but it isn’t the product the launcher is for: agent might be Grok’s rather than Cursor’s, or copilot AWS’s rather than GitHub’s. Hover the status for what TermHQ found. If the right one is installed under another name or path, put that in the command.

I cannot find the waiting-pane list

The waiting item in the bottom status bar is hidden when there are no waiting notices. Enable Settings → Agents → Show waiting panes in the status bar, then Always show it, even when nothing is waiting if you want it visible all the time — it then reads 0 waiting while the list is empty. An empty list says Nothing waiting right now.

Not every quiet terminal raises a notice: fresh startup output, short commands, and work you watched happen are ignored. If TermHQ was in the background when the pane went quiet, it also sends a native OS notification, and the waiting entry is recorded either way. If those notifications are missing, check your operating system’s notification permissions and Do Not Disturb settings as well.

Waiting notices do not time out. Return to the pane, or use the notice’s × — or Dismiss all — to clear them. Dismissing a notice does not stop the command. If an agent is flagged during a normal pause, increase Quiet seconds before badge under Settings → Agents. See When a pane needs your attention.

A shell is missing from the list

TermHQ detects shells at startup. Something installed afterwards appears after a restart.

On Windows, WSL distributions are listed individually; a distribution that is installed but not yet initialized will not appear until it has been run once.

Vim’s shortcuts trigger TermHQ actions

On Windows, Ctrl+B toggles TermHQ’s sidebar by default, but Vim uses it to page backward in normal mode. Similarly, Ctrl+F opens TermHQ’s find instead of paging forward in Vim.

Rebind or clear the corresponding TermHQ actions in Settings → Shortcuts, or turn on Ultra focus with Ctrl+Shift+U to pass shortcuts through to Vim. Press the same shortcut again to leave Ultra focus.

On macOS, the sidebar and find use ⌘, leaving Vim’s Ctrl shortcuts available. For other conflicts and Ultra focus behavior, see Keyboard shortcuts.

My terminals did not come back

Terminals survive quitting TermHQ, but not everything:

  • A restart or shutdown ends them. Nothing survives that — you get your panes and directories back, at fresh prompts.
  • Installing an update restarts the shells too. Your panes return, but running commands and agents need to be started again.
  • A program that exited on its own — an agent that finished, a build that ended — is gone because it ended, not because TermHQ lost it.
  • Turning off “Keep shells running after close” (Settings → Workspaces) makes closing a window end its terminals deliberately.
  • An SSH pane whose ssh process is gone — after a restart, say — comes back in its place reading Not connected until you reconnect — see SSH connections.

If panes come back but look emptier than you left them, the terminals are fine — only recent output is kept, and a chatty program pushes the rest out.

Everything vanished right after a crash

Relaunching within about fifteen seconds of a crash can open a fresh, empty workspace instead of the one you lost.

Your work is not gone. The terminals are still running. Quit and open TermHQ again, or open a second window, and they are adopted back.

TermHQ shows an error recovery card

Choose Reload. The card replaces the old blank-screen failure mode and includes the error details needed for a useful bug report. Your shells remain safe in the background while the interface reloads.

If the card appeared while previewing an imported theme, TermHQ normally keeps the last theme that applied successfully. Include the card’s details when reporting the theme that triggered it.

TermHQ says your settings file couldn’t be read

config.json held something TermHQ could not read past — usually a typo in a hand edit, or a value of the wrong type. TermHQ started with default settings, kept your file as config.json.broken- followed by the UTC time, and says so in a notice that quotes the error, line and column included. Your favorites, agents and shortcuts are in that copy, not lost.

  1. Choose Open folder to see the copy.
  2. Quit TermHQ.
  3. Fix what the error points to and save the corrected file as config.json.
  4. Start TermHQ again.

Dismiss only hides the notice. A different message, Settings weren’t saved with Retry, means a write failed rather than a read: your change is active in the window, and Retry saves it. See Configuration.

Output looks mangled after resuming

Usually a width mismatch: a shell drew its prompt at one size and came back at another. TermHQ restores each pane at the size it was to avoid this, but a shell with an unusual prompt can still be confused by it.

Pressing Enter to redraw the prompt fixes the display. clear fixes it thoroughly.

A plain click only focuses the pane. Ctrl+click a link (⌘+click on macOS) to open it in your default browser, or add Shift to open it in a browser pane beside the terminal — hovering a link shows the same hint. Only http and https links open, and each is handed to the operating system as an address, never run as a command.

Right-click shows a menu instead of pasting, or the reverse

On macOS a right-click opens a menu — Copy, Paste, Select all, Clear and Find. Elsewhere it copies the selection if there is one and pastes otherwise, the Windows console habit. Settings → Terminal → Right-click in a terminal picks either behavior on any platform.

Dictation does nothing

If there is no mic button at all, no speech model is installed yet — that is the intended off state, not a bug. Open Settings → Voice, download a model (or import your own), close Settings, and the button appears. The panel says at the top whether dictation can run on this build at all and whether a model is ready, before it offers anything to download.

If the button is there but nothing comes out, use Settings → Voice → Test microphone: it records a few seconds and plays them back through the same capture path dictation uses. A silent clip means the operating system is not giving TermHQ any audio — check the microphone permission for TermHQ in your system settings, and the Microphone setting in Settings → Voice if you have more than one. The mini-waveform beside the mic button tells the same story live: it scrolls with real input, so a flat line means no audio is arriving.

On macOS the permission matters twice over: without it, microphones do not enumerate at all, so the device list comes up empty rather than wrong.

When dictation cannot start or finish, the status bar says why; hover the notice for the fix:

  • Dictation: The microphone is blocked — allow microphone access for TermHQ in your system’s privacy settings, then try again.
  • Dictation: No microphone was found — plug one in, or pick another in Settings → Voice.
  • Dictation: The microphone is busy — another app may be holding it; close that app, then try again.
  • Dictation: No speech model is installed — download one in Settings → Voice.
  • Dictation: Transcription failed — the hover text carries the transcriber’s own reason.
  • Nothing to dictate into — the words need somewhere to go. Focus a terminal, or click into a text field, then start dictation.

Linux support is pending. See Installation.

If it hears you but the words come out wrong, check the dictation language in Settings → Voice — and note that models labeled English only stay English whatever the language is set to; only multilingual models follow it.

If the words landed in a different pane than you expected: they go to the terminal you started dictating in, whatever you clicked since. The full feature — starting it, Hold to talk, the cursor — is on the Dictation page.

My language server is not doing anything

TermHQ ships no language servers — they are programs you install yourself. Open Settings → Editor, expand Language server setup (it starts collapsed), and read the status chip beside the one you expect:

  • not installed — the command is not on your PATH. Install it; pressing Restart will not help, which is why the chip keeps saying this.
  • would not start — it is installed but failed. Hover the chip for why the launch failed, and use Logs for the server’s own output.
  • starting… for a long time — a large project on first open, usually. Rust and TypeScript both index before they answer.
  • restarting… — it crashed after running; a fresh launch follows in a moment, and Logs has what it said on the way out.
  • Nothing at all — check the Language intelligence master switch, and that the entry itself is enabled.

See Language servers for the whole picture.

Format on save is not formatting

Formatting comes from your language server, not from TermHQ — so a language with no server installed has no formatter. Check the server’s status under Settings → Editor → Language server setup first.

If a server is running and you are getting a different result than you expect, the first ready server in the list that offers formatting is the one that owns it. Settings cannot reorder that list: its order is the languageServers array in config.json, so move an entry earlier there — with TermHQ closed — to hand it formatting. Format on save also gives up after two seconds rather than making you wait on a slow formatter.

A file I am editing changed on its own

That is an agent, a formatter, or a git checkout — and it is handled rather than ignored. With no unsaved edits the tab reloads quietly, keeping your cursor and undo history. With unsaved edits you get a card offering Compare, Reload from disk or Keep my changes. Nothing is overwritten without you picking one.

I lost unsaved edits

Two different cases:

  • After a crash or power cut, you should not have. Reopen the file and the tab comes back still unsaved. If it did not, check Settings → Editor → Recover unsaved changes after a crash — and note that text over 4 MB is never mirrored.
  • After quitting normally, unsaved buffers are deliberately not kept. Quitting with unsaved work stops and asks first, so Quit without saving is the only way past it.

A browser pane looks frozen

Almost certainly it is — deliberately, and only while something covers it or moves it. A browser pane is a native surface that the interface cannot paint over, so whenever a modal, menu, or drag preview needs the space, or the panes glide into new places, the pane shows a stand-in until the overlay goes away or the pane lands. On Windows the stand-in is a still frame of the page; on macOS it is the pane’s plain background. Audio and video keep running underneath. Opening the waiting-pane list, closed-pane list or stash shelf has the same effect. Their buttons in the status bar do not freeze the page while those lists are closed.

On Windows you sometimes get the plain background instead of a still frame: a pane nobody can see does not pay to capture one, and neither does a second overlay arriving right behind the last. Both go live again the moment the overlay does.

If nothing is covering it and it is still frozen, reload the page from the pane’s reload button.

A browser pane’s mute button does nothing

Muting works on Windows, and on macOS where the system’s WebKit supports page audio control. On a macOS version without it, pressing the speaker shows an error in the pane saying page audio control is unavailable, and Settings → Browser → Sound in new panes cannot start a pane muted there either.

My shortcuts do nothing while a web page is focused

TermHQ’s chords work over a focused page on Windows and macOS, except a short list the page keeps for itself: find (Ctrl+F, or ⌘+F on macOS), page zoom and copy, plus the agent picker and dictation, which only make sense in a terminal — see Keyboard shortcuts. If every chord seems dead, check for Ultra focus: while it is on, the page gets every key except Ultra focus’s own chord.

My background does not show

Read what Settings → Appearance → Background says under the tiles:

  • could not be shown here: the webview cannot decode it — your system’s webview cannot play that file, so the grid stays plain. MP4 (H.264) and WebM play everywhere; PNG, JPEG, WebP and GIF always show. Convert the file, or choose Try again after a passing failure.
  • is no longer in the backgrounds folder, so nothing is shown — the file was deleted or renamed in backgrounds/. Pick another, or add it again.

A file over 1 GB is refused when you add it, with its size in the message.

On macOS a GIF plays at its own pace, which is why it gets no Speed row there; videos follow Speed on both platforms. And terminal text a touch softer while a background is set is expected: the terminal draws on a see-through surface then. Choose None and it is sharp again.

SSH connections

The whole feature is on the SSH connections page.

  • There is no Connect via SSH. SSH is off until you turn on Settings → SSH → SSH connections. Until then the + button’s shell list has no SSH row, and the command palette lists Connect via SSH but refuses it, saying where to turn it on.
  • No OpenSSH client was found. TermHQ uses the OpenSSH client already on your machine and installs none. On Windows, add Windows’ own client (Settings → Apps → Optional features → OpenSSH Client), or install Git for Windows, which carries another. macOS includes one at /usr/bin/ssh. For a client somewhere else, choose A path… under Settings → SSH → OpenSSH client.
  • ssh ended with code 255. That is OpenSSH’s code for any connection or authentication failure alike — a refused connection, an unknown host, a rejected key or password. The output above the card says which. The card also shows the exact command the pane ran (hover it for all of it), and Reconnect — or Enter in the pane — tries again.
  • Idle connections drop. A NAT or a firewall can drop a quiet connection without a word. Settings → SSH → Keep idle connections alive sends a keep-alive every 30 seconds by default; set to off, your ssh config’s own ServerAliveInterval decides.
  • My ssh_config aliases are missing. The picker lists concrete Host entries only; wildcard patterns and Match blocks are left out. The line under Settings → SSH → OpenSSH client names the config file they come from, or says it was not found.
  • My keys work in one terminal but not in TermHQ (Windows). Windows OpenSSH and Git for Windows’s client do not share keys, agents or config. The client chosen in Settings → SSH is the one in play; pick the other if that is where your keys live.
  • An SSH pane says Not connected after a restart. By design: restoring a workspace puts the pane back in its place without connecting, so a workspace with several remote panes does not open with a pile of password prompts. Press Enter or Reconnect when you want it. A pane whose ssh was still running in the background comes back connected.
  • My saved profiles are gone. If ssh-profiles.json cannot be read — a hand edit gone wrong, or a file from a newer TermHQ — the picker says so and leaves the file exactly as it is. Typed targets still connect, and nothing is written over it.

Passwords, passphrases and host-key questions are OpenSSH’s own and appear in the pane; you answer them there.

There is nothing to grab between my panes

Check Settings → Appearance → Resize panes by dragging. Off is a supported state — equal shares and no handles — and it is remembered per machine, so a config carried from elsewhere can arrive with it already off.

My pane sizes keep resetting

By design, and only on one trigger: opening or closing a pane — including stashing one or bringing it back — puts every boundary back to equal. A hand-tuned layout describes a particular set of panes, so it is not carried onto a different one. Moving, swapping, growing, arranging and resizing the window all leave your proportions alone, and a workspace keeps them across restarts. See Resizing panes.

To level the grid deliberately, use the reset button that appears in the title bar beside the layout switch whenever a pane is off its equal share, or the Reset pane sizes action — unassigned by default, so run it from the command palette or bind it in Settings → Shortcuts. To even up just one pair, double-click the boundary between them, or Tab to it and press Enter.

Windows warns about the installer

SmartScreen warns on the first install of a build that is not code-signed. See Installation.

Source Control says it cannot read a WSL repo

Repositories on a \\wsl.localhost path are not supported by Source Control yet, and it says so rather than showing you something wrong. Git inside the WSL pane itself works normally.

A checkout is missing from Worktrees

Open Settings → Git → Worktree roots and confirm the folder is still listed. The tracker looks for checkouts up to two levels beneath each configured root; it does not crawl outside them. Add a closer root if the checkout is nested more deeply, then open the Worktrees view and choose Refresh.

If a configured root moved or is no longer available, the Worktrees view keeps the item visible and shows the reason instead of silently dropping it.

An update cannot finish

Open Settings → General → Updates to read the result and use Check now or retry Update and restart. Automatic checks stay quiet when you are offline; a manual check reports the connection problem.

A failed download or signature check leaves your running session in place. If another TermHQ window is still open, switch to it and answer any unsaved-file prompt before retrying. A workspace-save failure also stops installation before shells are shut down.

An installer failure after shutdown is different: TermHQ restores terminal availability, but commands that stopped are not resumed. Review the error and your work before trying again. See Updating.

Where the log is

pty-host.log, directly inside the configuration directory (Configuration). Attach it to any bug report about terminals not starting, dying, or failing to come back.

It starts empty whenever a new background host starts — after your computer restarts, after an update, or after a quit that left no shells running. With Keep shells running after close on, relaunching TermHQ reconnects to the same host and the log carries on. Grab a copy before anything restarts the host if you are chasing something that happened in a previous run.

Reporting a bug

Open an issue on GitHub with:

  • your operating system and version
  • your TermHQ version (Settings → General → Updates shows it)
  • what you expected, and what happened instead
  • pty-host.log, if it involves terminals not behaving
Type to search the documentation.
↑ ↓ navigate↵ openEsc close