Skip to content

Integrated Terminal

Workbench includes a full-featured terminal emulator built with xterm.js and portable-pty, running natively alongside your agent sessions.

Toggle the terminal panel using the dedicated composer button next to + in the chat composer, or with ⌘/Ctrl + `. The terminal opens in the current workspace’s worktree directory, so you’re always in the right context.

The composer button replaces the earlier attach-menu entry, putting terminal access one click away without opening a dropdown first.

You can open multiple terminal tabs within each workspace. Each tab runs its own shell session in the workspace’s worktree.

When the agent runs background commands (tool calls that execute shell commands), each background command gets its own terminal tab so you can watch its output live. Background tabs support the same drag reordering and right-click context menu as user-created tabs.

Repositories using the trunk workflow strategy get a persistent Repo terminal tab. This tab is tied to the repository rather than to a single workspace, so it survives workspace switches and gives you a stable place to run builds, migrations, or other repo-wide tasks.

Every terminal tab can be split into multiple panes side-by-side or stacked, so you can run a dev server, tail logs, and execute tests without leaving the workspace.

  • Split side-by-side (vertical divider): ⌘D on macOS, Ctrl+Shift+D on Linux/Windows.
  • Split stacked (horizontal divider): ⌘⇧D on macOS, Ctrl+Shift+Alt+D on Linux/Windows.
  • Close the focused pane: ⌘W on macOS, Ctrl+Shift+W on Linux/Windows. When only one pane is left, this closes the enclosing tab.
  • Move focus between panes: ⌘⌥←/→/↑/↓ on macOS, Ctrl+Alt+←/→/↑/↓ on Linux. You can also click any pane to focus it.
  • Resize: drag the divider between two panes.
  • Zoom terminal text only: ⌘/Ctrl + Shift + = to increase terminal font size, ⌘/Ctrl + Shift + - to decrease it.

Each pane runs its own independent PTY in the workspace’s worktree. Up to six panes are supported per tab to keep the layout usable.

Split layouts are ephemeral — the app reopens each tab as a single pane on restart. Tab identity and titles are persisted; the split arrangement within a tab is not.

Shells live in the Rust backend, not the webview — so a frontend reload (including an automatic watchdog recovery) doesn’t kill them. Each pane records a stable identity when it spawns its shell; after a reload, the rebuilt pane finds its own still-running shell, re-attaches, and replays recent output (up to 256 KiB of scrollback kept backend-side per terminal). A build or dev server running in a terminal keeps running straight through a reload, and the pane picks up where it left off instead of showing a fresh empty prompt.

Closing a pane or tab still terminates its shell — durability applies to reloads and recoveries, not deliberate closes. Shells only end when you close them, when they exit on their own, or when the app quits.

Each PTY launches your platform’s interactive shell, with that shell’s normal profile loading mechanism intact — so prompts, aliases, modules, and direnv/mise/etc. integrations from your dotfiles all work.

$SHELL is honoured if set; otherwise /bin/zsh (macOS) or /bin/bash (Linux). The shell’s regular profile (~/.zshrc, ~/.bashrc, etc.) loads as it would in any other terminal.

pwsh.exe (PowerShell 7+) and powershell.exe (Windows PowerShell 5.1) read profiles from totally different paths — Documents\PowerShell\… vs Documents\WindowsPowerShell\… — so blindly preferring PS7 leaves PS5.1 users staring at an unconfigured banner. Workbench’s resolution is profile-aware: it picks the PowerShell flavour whose profile you’ve actually written.

  1. pwsh.exe on PATH and a PS7 profile exists
  2. powershell.exe on PATH and a PS5.1 profile exists (and there’s no PS7 profile)
  3. pwsh.exe on PATH (modern default when no profile signal either way)
  4. powershell.exe on PATH (in-box fallback)
  5. %ComSpec% (deliberate cmd.exe override, if set)
  6. %WINDIR%\System32\cmd.exe (always-present last resort)

Profile detection probes both %USERPROFILE%\Documents\… and %USERPROFILE%\OneDrive\Documents\… (Office 365 and Windows 11 Backup commonly redirect Documents into OneDrive). Both per-host (Microsoft.PowerShell_profile.ps1) and all-hosts (Profile.ps1) profiles count.

No extra arguments are passed, so the shell behaves the same as it would in a stock Windows Terminal tab — PowerShell auto-loads $PROFILE, and cmd.exe honours its HKCU\Software\Microsoft\Command Processor\AutoRun entry.

If the workspace has a flake.nix (or a legacy shell.nix) and the bundled env-nix-devshell environment provider is enabled, the terminal launches inside that workspace’s devshell — Workbench spawns it as plain nix develop. The toolchain pinned by the flake is on PATH from the first prompt, so the integrated terminal matches what nix develop gives you outside Workbench, regardless of which devshell Workbench itself was started in.

Because the terminal runs nix develop with no --command, a devshell workspace’s terminal is the devshell’s own shell — the flake’s shellHook runs on entry. It deliberately does not launch your personal interactive shell (zsh/bash with your dotfiles) inside the devshell: re-running a full shell profile inside nix develop re-applies login-level environment setup (oh-my-zsh, nix-daemon.sh, and on nix-darwin the /etc/zshenv reset) that overwrites PATH and strips the devshell back out. Non-devshell workspaces still open your normal shell as before.

It falls back to a plain shell only when there is genuinely nothing to enter — the provider is disabled, nix is not installed, or the workspace has no flake. A flake that fails to evaluate is not hidden: nix develop reports the error directly in the terminal, so a broken devshell is visible rather than silently swapped for a plain shell with the wrong toolchain. This is independent of env-direnv — the terminal enters the devshell through nix develop directly, never through direnv. Toggle it per repo or globally from the env-nix-devshell entry in Settings > Plugins.

Agent subprocesses use the same separation. In a Nix devshell workspace, Workbench starts the harness as nix develop --command <agent> ..., so agents see the clean devshell environment rather than direnv’s user-shell/profile environment.

Adjust the terminal font size in Settings > Appearance > Terminal font size (range: 8–32px, default: 11px). Press ⌘/Ctrl + Shift + = or ⌘/Ctrl + Shift + - to scale only the terminal without changing the rest of the UI.

The terminal zoom level is independent from the main UI zoom. Increasing or decreasing the global UI font size (⌘/Ctrl + = / ⌘/Ctrl + -) does not affect the terminal, and vice versa. This lets you keep a comfortable reading size in the chat panel while using a smaller or larger font in the terminal.

Select text with the mouse, then press ⌘C on macOS or Ctrl+Shift+C on Linux/Windows to copy it to your clipboard (the default is rebindable under Settings > Keyboard > Terminal > Copy selection). Right-click the pane for Copy / Paste menu entries. Copies are trimmed the way native terminals do it — trailing cell padding and empty rows below the last line of output are dropped. With nothing selected the key reaches the shell unchanged.

Paste with ⌘V / Ctrl+Shift+V.

Terminal panes honour the OSC 52 clipboard escape, so a program running in the shell can place text on your clipboard directly — Claude Code’s “press c to copy the login URL”, tmux set -g set-clipboard on, neovim with an OSC 52 clipboard provider, and similar tools all work. This matters most for remote workspaces: the program runs on the serving machine, but the text lands on the clipboard of the machine you’re sitting at. Clipboard read requests from the shell are always refused, so a remote process can never read your local clipboard.

Press ⌘/Ctrl + F while a terminal pane has focus to open an in-panel search bar for that pane’s scrollback. Enter steps to the next match; Shift + Enter steps to the previous one; Esc closes the bar. The same shortcut still searches the active chat transcript when focus is elsewhere — it routes by which surface owns the keystroke, not by which panel is visible.

The keybinding is rebindable from Settings > Keyboard > Terminal > Search terminal scrollback independently of the chat search hotkey, so you can split the two if you prefer.

The chat composer supports a shell command mode that lets you run commands directly from the chat input without switching to a terminal tab. Type a shell command and send it — Workbench executes it in the workspace’s worktree and streams the output inline. This is useful for quick one-off commands where opening a full terminal tab feels heavyweight.

Every terminal session has workspace environment variables set automatically — $WORKBENCH_WORKSPACE_NAME, $WORKBENCH_WORKSPACE_PATH, $WORKBENCH_ROOT_PATH, and others. These are useful for scripts and tools that need to know which workspace they’re running in.

The sidebar shows the foreground command running in each workspace’s terminal. Detection is automatic — Workbench polls the PTY’s foreground process group, so any shell works (zsh, bash, fish, anything else) with no configuration required and no changes to your shell rc files.

The indicator is macOS and Linux only — Windows has no equivalent of process-group ownership on PTYs, so the sidebar simply omits the indicator there. The polling path also only observes start/stop transitions, not exit codes, so there’s no separate “succeeded vs. failed” colorization.


Original source: utensils.io/claudette