Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

settings.json

~/.termherd/settings.json                     (macOS, Linux)
%USERPROFILE%\.termherd\settings.json         (Windows)

There is no in-app settings panel yet: edit the file and restart.

The annotated template with every option, its default and its meaning is docs/settings.example.jsonc — copy the blocks you want and strip the comments. The real file is strict JSON: no comments, no trailing commas.

How it loads

Read once at startup, and defensively:

  • Every field is optional. A missing file, a missing field, or a corrupt file falls back to built-in defaults — settings never block startup.
  • Out-of-range values clamp instead of failing the file.
  • One bad value — a typo’d colour, an unknown action name — degrades alone with a logged warning. The rest of the file still applies.

Two neighbouring files are TermHerd’s, not yours to edit: window.json (size and position — a position left off every connected monitor is dropped, so the window re-centers instead of opening out of reach) and metadata.json (stars, archives, custom titles, and the repositories you added by hand).

Options

shell

The program launched for each session. Omit the block, or set it to null, for the platform default login shell. args is optional.

"shell": { "program": "pwsh", "args": [] }

Naming your shell here has a side effect worth knowing: bash and fish get their OSC 133 shell-integration snippet — and therefore an accurate activity status — only when named explicitly. See Status and attention.

theme

"dark" (default) or "light". GUI chrome only — sidebar, tab strip, buttons. The terminal grid keeps its own colours.

close

Per-action close confirmation. Both keys default to "confirmWhenActive".

"close": { "tab": "confirmWhenActive", "app": "confirmWhenActive" }
ValueBehaviour
alwaysConfirmalways ask
confirmWhenActiveask only while a session runs a foreground process
noConfirmationnever ask

terminal

"terminal": {
  "font_size": 14,
  "copy_on_select": false,
  "paste_on_right_click": false,
  "colors": {
    "scheme": "solarized-dark",
    "foreground": "#839496",
    "background": "#002b36",
    "cursor": "#839496",
    "palette": ["#073642", "#dc322f", "…16 entries…"]
  }
}
KeyDefaultNotes
font_size14pixels, clamped to 6–40. The zoom chords step from here at runtime without rewriting it.
copy_on_selectfalsea drag release or a double-click copies the selection outright, no chord needed
paste_on_right_clickfalsea right-click pastes into the pane under the pointer, not necessarily the focused one
colors.schemebuilt-insolarized-dark, solarized-light, gruvbox-dark, gruvbox-light
colors.foreground / .background / .cursorfrom the scheme"#rrggbb"; the # is optional
colors.palettefrom the schemethe 16 ANSI colours — normal 0–7, then bright 8–15

Every colour field is optional and overrides the scheme it starts from. Fewer than 16 palette entries override the head of the list; entries past 16 are ignored.

"sidebar": { "session_limit": 5 }

Sessions shown per project before the tail folds behind a … N more expander. 0 shows every session.

record

The GIF screencast budget (Cmd/Ctrl+Shift+R). Values clamp: fps 1–60, max_seconds 1–600, scale 0.1–1.0.

"record": { "fps": 8, "max_seconds": 30, "scale": 0.5 }

mcp

Whether the live bridge’s prompt_in_session may prompt another Claude session — one agent driving another. Off by default; a shell session is never gated. A single call can opt in on its own with allow_claude_nesting: true (see The live bridge).

"mcp": { "allow_claude_nesting": false }

open

The command a Cmd/Ctrl-clicked file path opens in. Omit the block to hand the file to the OS default handler (open / explorer / xdg-open) — the default, which cannot honour a line number.

"open": { "command": "code -g {path}:{line}:{col}" }

Templates: {path} (required), {line}, {col}. A path the terminal printed without a position opens at 1:1, so one command stays well-formed either way.

RuleWhy
Give a GUI editorthe child’s standard streams are closed, so vim would start invisible and unkillable. Reach one through a terminal emulator: ["wezterm", "start", "--", "vim", "+{line}", "{path}"]
Run as argv, never a shellthe string is split on whitespace before {path} is filled in, so a filename with spaces or & can never become a second argument. Use the array form when the program’s own path has spaces
No ~, no shell lookupthe program is spawned directly; write the full path. An app launched from Finder/Explorer inherits a minimal PATH that often lacks code
Windows: code.cmda direct spawn only ever appends .exe, so a bare "code" is not found
A placeholder in the program name is refusedwhat the terminal printed chooses the file, never the executable

An empty command, one without {path}, or one with an unknown placeholder is logged and ignored — the OS handoff applies instead. A command that fails to start raises a desktop notification.

Configuring this also lifts a restriction: with no command, a path the OS would run rather than show (.app, .exe, .desktop) is neither underlined nor opened, because the handoff obeys the file association. An explicit editor consults no association, so those files open like any other.

keys

Keyboard overrides — one chord or a list per action, replacing that action’s default. The full vocabulary and its defaults are in Keyboard shortcuts.

"keys": {
  "copy": "ctrl+y",
  "paste": ["ctrl+shift+v", "shift+insert"],
  "activate-tab-1": "alt+1"
}

Reading and writing it from a Claude session

The stdio MCP server exposes a subset of these options as list_options / set_option, so you can ask “what can I configure here?” or “switch me to a light theme” from any Claude session.

The eight ids it covers today: theme, shell.program, shell.args, terminal.colors.scheme, terminal.colors.foreground, terminal.colors.background, terminal.colors.cursor, terminal.colors.palette. Two of them — shell.program and shell.args — are read-only over MCP: they name what TermHerd executes at the next launch, so an agent may read them but never set them. The close, sidebar, record, open, mcp, keys, terminal.font_size, terminal.copy_on_select and terminal.paste_on_right_click blocks are file-only for now; keys is published as a read-only resource.

A set_option write lands in settings.json and applies on restart, like any other edit to the file.

A complete example

{
  "shell": { "program": "/bin/zsh" },
  "theme": "dark",
  "close": { "tab": "confirmWhenActive", "app": "alwaysConfirm" },
  "terminal": {
    "font_size": 15,
    "copy_on_select": true,
    "paste_on_right_click": true,
    "colors": { "scheme": "gruvbox-dark" }
  },
  "sidebar": { "session_limit": 0 },
  "record": { "fps": 10, "max_seconds": 20, "scale": 0.5 },
  "open": { "command": "code -g {path}:{line}:{col}" },
  "mcp": { "allow_claude_nesting": false },
  "keys": {
    "toggle-sidebar": "ctrl+alt+b",
    "focus-next": "ctrl+alt+right"
  }
}