Skip to content

Integrated Terminal ​

VMark includes a built-in terminal panel so you can run commands without leaving the editor.

Press Ctrl + ` to show or hide the terminal panel. Opening it puts the caret in the shell, and closing it gives the caret back to the editor — so the panel is reachable and escapable without touching the mouse.

To move between the editor and an OPEN terminal without hiding it, press Ctrl + Shift + ` (Focus Terminal or Editor; Alt + Shift + ` on Windows and Linux). It toggles in both directions and never changes the panel's visibility — if the terminal happens to be hidden, it opens it rather than doing nothing.

Sessions ​

The terminal supports up to 5 concurrent sessions, each with its own shell process. A vertical tab bar on the right side shows numbered session tabs.

ActionHow
New sessionClick the + button
Switch sessionClick a tab number
Close sessionClick the trash icon
Restart shellClick the restart icon
Rename sessionDouble-click a tab, type a name, press Enter (Escape cancels)
Swap panel sideClick the swap icon (↕ / ↔) to flip the terminal to the opposite side of its current axis. In Auto mode this keeps the smart aspect-based switching (landscape → side, portrait → bottom/top) — it just chooses the other end.
Maximize the panelDouble-click the resize handle; double-click again to restore

When you close the last session the panel hides but the session stays alive — reopen with Ctrl + ` and you are back where you left off. When the shell exits cleanly (exit or Ctrl + D), its tab closes automatically — and the panel hides if it was the last one. If the shell exits with an error, the tab stays open showing the exit code; press any key to restart it.

Closing a session — with the trash icon, by closing its window, or by quitting VMark — ends everything started in it, not just the shell. VMark sends a hangup signal (SIGHUP) to the shell's whole process group, waits up to a second for it to exit, then force-kills (SIGKILL) whatever is left. A job you deliberately detached into its own process group (for example with nohup or setsid) is not affected. On Windows there is no hangup step: the shell is ended at once.

Notifications: when a terminal rings the bell (e.g. Claude Code finishing a turn) while that VMark window isn't focused, VMark posts an OS notification naming the window's document — so you can run Claude Code across several windows and get pinged for whichever needs you, without watching each one. Toggle it with Settings → Terminal → Notify when unfocused (on by default; asks for notification permission on first use). The same unfocused-bell signal also flags the window in the Window Status panel, so you can see which window needs you and jump straight to it.

Each tab reflects the running program's title (set by tools that emit a terminal title, such as vim or ssh) unless you have manually renamed the session — a manual rename always wins. To rename, double-click the tab: Enter commits, Escape discards, and clicking away keeps what you typed. An empty name is ignored.

Maximizing: the panel's size stops at 80 % of the available space so the editor stays reachable, and a double-click on the resize handle snaps it to that cap. A second double-click returns it to your saved size. This is a view toggle — it never changes the size you configured.

Open Terminal Here: right-click any folder in the file explorer and choose Open Terminal Here to start a session in that directory. The new session opens there regardless of where your other sessions happen to be. At five sessions the item is greyed out.

Terminal sessions and the workspace rail ​

With the workspace rail enabled, each workspace on the rail owns its own set of terminal sessions. Switching workspaces swaps the visible terminal tabs — the hidden workspace's shells stay exactly where they were: alive, same working directory, nothing typed into them. Switching back reveals the same shells again, and the session you were looking at is remembered per workspace.

  • New sessions belong to the workspace that was active when they were created, and start in that workspace's root.
  • The 5-session cap and the Terminal 1…5 numbering apply to the visible set — hidden workspaces' sessions do not consume the active workspace's headroom.
  • Opening the panel over a workspace with no sessions creates one there automatically; without a workspace (or a saved file to anchor a directory) the panel shows a hint instead.
  • Closing a workspace from the rail, or moving it to its own window, closes its terminal sessions with it.
  • With the rail off, everything behaves as before: one window-wide session set whose idle shells follow workspace switches with a cd.

Keyboard Shortcuts ​

These shortcuts work when the terminal panel is focused:

ActionShortcut
CopyMod + C (with selection)
PasteMod + V
ClearMod + K
SearchMod + F
Line start / endCmd + ← / Cmd + → (macOS)
Delete lineCmd + ⌫ (macOS)
Zoom terminal fontMod + = / Mod + - / Mod + 0
Select all terminal outputMod + A
Switch to session 1 … 5Mod + 1 … Mod + 5
Toggle TerminalCtrl + `
Focus Terminal or EditorCtrl + Shift + `
Previous command promptMod + ↑
Next command promptMod + ↓

When the terminal is focused, Mod + = / - / 0 zoom the terminal font (set separately in Terminal settings), not the editor font, and Mod + F opens the terminal search rather than the editor's find bar.

Prompt navigation (Mod + ↑ / Mod + ↓) requires shell integration — see Shell integration below.

Linux: Ctrl + a letter goes to the shell, so readline keys such as Ctrl + A, Ctrl + E, Ctrl + K, Ctrl + F, Ctrl + U and Ctrl + W work as in any Linux terminal. The terminal's own letter shortcuts move to Ctrl + Shift: Ctrl + Shift + F searches, Ctrl + Shift + K clears, Ctrl + Shift + A selects all, and Ctrl + Shift + C / Ctrl + Shift + V copy and paste. Ctrl + C still copies a selection (otherwise it sends SIGINT) and Ctrl + V still pastes; Ctrl + Insert / Shift + Insert also copy and paste.

TIP

Mod + C without a text selection sends SIGINT to the running process — the same as pressing Ctrl+C in a regular terminal.

Reading scrollback while typing ​

Scroll up to read earlier output and keep typing: the viewport stays where you are, and a floating prompt appears at the bottom of the terminal with a live copy of the rows you are typing into — the shell prompt, or the input box of a TUI such as Claude Code. Keys still go to the shell, so tab completion, history and input methods work as usual. Click the arrow at its right end to jump back to the prompt; it disappears on its own once the prompt is back in view. Pressing Enter or Ctrl+C also jumps back, so you see what the command — or the prompt you sent to a TUI — does next; every other key, including Shift+Enter, leaves the viewport alone. Full-screen programs (vim, less) have no scrollback, so it never appears there.

Press Mod + F to open the search bar. Type to search incrementally through the terminal buffer.

ActionShortcut
Next matchEnter
Previous matchShift + Enter
Close searchEscape

The bar reports what it found next to the input:

  • 3 / 17 — you are on the third of seventeen matches.
  • 5000 matches — too many matches for the terminal to track which one is active, so it reports the total without a position.
  • No results — the query matched nothing; the input text turns red as well.

Three toggles sit between the input and the arrows:

ToggleEffect
AaMatch case
abMatch whole words only
.*Treat the query as a regular expression

While regex mode is on, a half-typed pattern ([ on the way to [a-z]) simply reports no results instead of erroring — keep typing. The toggles reset each time you close the bar or switch sessions.

Context Menu ​

Right-click inside the terminal to access:

  • Copy — copy selected text (disabled when nothing is selected)
  • Copy Unwrapped — copy the selection with display-width line breaks removed. Some command-line programs (codex and other TUI apps) hard-wrap their output to the terminal width by inserting real newlines; a normal copy preserves those breaks. "Copy Unwrapped" joins wrapped lines back into continuous paragraphs (blank lines are kept as paragraph breaks). It is CJK-aware — Chinese/Japanese text joins without inserting spaces. Select the block you know is one logical flow, since VMark can't tell a wrap newline from an intentional one.
  • Paste — paste from clipboard into the shell
  • Select All — select the entire terminal buffer
  • Clear — clear visible output
  • Reset Display — re-paint the terminal and reset its rendering cache. Use this if characters start to overlap, mix cases, or render garbled after a long session — most often seen when running heavily styled CLIs (e.g. Claude Code) for hours. Terminals in the same window share one glyph cache, so this re-paints every terminal in the window rather than only the active tab.
  • Copy Command Output — copy everything one command printed, without its prompt line and without the next command's output. Appears only when you right-click inside a command's output and shell integration is on, since that is what tells VMark where each command began and ended.

The menu is fully keyboard-navigable: it opens with the first available action focused, arrow keys move between items (skipping disabled ones), Home/End jump to the first/last, Enter or Space activates, and Escape or Tab closes it.

Running a code block ​

Hover any bash, sh, zsh or shell fence — or a transcript fence tagged console, shell-session, shellsession or terminal — in your document and a ▶ Run in Terminal button appears beside the copy button. It pastes the block into the terminal — revealing the panel and starting a session if needed — and stops there.

It pastes; it does not run

The command is placed on the shell's input line and never executed for you: no newline is appended, so nothing happens until you press Enter. Read what landed there first — a document can come from anywhere, and a code fence is just text somebody wrote.

For a transcript fence (console, shell-session, shellsession, terminal) — a pasted session — leading $ , % , and # prompts are stripped so you get the command rather than the prompt. In a bash fence they are left alone, since there they are source code.

The terminal detects three kinds of links in command output:

  • Web URLs — click to open in your default browser
  • OSC 8 hyperlinks — explicit terminal hyperlinks emitted by tools like ls --hyperlink=auto, gh, and modern compilers. The visible text and the underlying URL can differ; clicking opens the URL.
  • File paths — a path containing a / and ending in a file extension; click to open the file in the editor (supports :line:col suffixes; a relative path resolves against the shell's current directory when shell integration reports it, otherwise against the workspace root)

Shell Environment ​

VMark sets these environment variables in every terminal session:

VariableValue
TERMxterm-256color
TERM_PROGRAMWezTerm
TERM_PROGRAM_VERSION20240203-110809-5046fc22
VMARK_WORKSPACEWorkspace root path (when a folder is open)
PATHFull login shell PATH (same as your system terminal)
COLORTERMtruecolor
LC_CTYPEUTF-8 — macOS only

TERM_PROGRAM reports WezTerm, not vmark, and that is deliberate. Several CLI tools — Claude Code's /terminal-setup among them — enable CSI u key encoding only for terminals on a hard-coded allowlist, and fall back to a degraded "unknown terminal" path for everything else. VMark speaks that protocol, so it identifies as the allowlisted terminal whose behavior it matches most closely. Changing this value to vmark would silently break Shift+Enter and other modified-key sequences in those tools. See ADR-006.

LC_CTYPE=UTF-8 is set on macOS only. A GUI app launched from the Dock or Spotlight inherits almost no environment there, so without it the shell falls back to the C locale and tools print ? for CJK text. The bare name UTF-8 is a locale on macOS and is not one on Linux, so setting it there would replace a perfectly good inherited locale with an invalid one — every program that calls setlocale() would complain. On Linux and Windows your desktop session's own LANG / LC_* are inherited unchanged.

VMark deliberately does not set EDITOR. Your own $EDITOR — whatever your shell config exports — is what git commit, crontab -e, and friends will launch. (VMark used to force EDITOR=vmark, but the vmark command-line shim is optional and returns immediately rather than waiting for you to close the tab, so git commit failed either with "command not found" or with an empty commit message. Making it work needs a blocking vmark --wait protocol, which is not built yet.)

The integrated terminal inherits your login shell's PATH, so CLI tools like node, claude, and other user-installed binaries are discoverable — just as they would be in a regular terminal window.

Unless you pick a shell in the terminal settings, VMark starts your login shell. A shell you pick must be one VMark offers — on macOS and Linux, a shell listed in /etc/shells (or your login shell) that exists and is executable; on Windows, PowerShell, pwsh, cmd.exe or %COMSPEC% — given as an absolute path. A saved choice that is no longer available shows as (unavailable) in the settings, and VMark starts your default shell instead. On macOS and Linux it reads the login shell from your user account entry first, then $SHELL, and falls back to /bin/sh. On Windows it uses %COMSPEC%, falling back to the full path of cmd.exe. The working directory starts at the workspace root, or the active file's parent directory, or $HOME.

Standard shell shortcuts like Ctrl+R (reverse history search in zsh/bash) work when the terminal is focused — they are not intercepted by the editor.

When the workspace root changes after the terminal is already running, idle sessions automatically cd to the new root. A session busy with a command (say, vim or less) is not interrupted: it changes directory once the command finishes, which needs shell integration to detect. With the workspace rail on, sessions that belong to a workspace keep their own directory.

Microphone, camera and Apple Events on macOS ​

Programs you run in the integrated terminal can ask for the microphone, the camera, or permission to control other apps (Apple Events, used by osascript). macOS asks under VMark's name, because it treats VMark as the app responsible for everything its terminal starts. Allow access when macOS asks; you can change it later in System Settings → Privacy & Security under Microphone, Camera or Automation. The request happens when a program first uses the resource, not when you open the terminal.

If a program gets silent audio, a black frame or a "not authorized" error and no prompt appears, check whether VMark is listed and allowed in that settings page. When reporting the problem, include the program's output.

For virtual audio inputs such as BlackHole, permission alone does not route audio. Select the intended input in your recording tool, route audio to it, and verify a short recording before a longer session: a growing audio file does not by itself prove that sound was captured. VMark does not include a recorder or transcriber; those come from tools you install separately.

Not yet implemented ​

These are tracked but do not ship today. They are listed here because earlier versions of this page described some of them as if they did:

  • Pause / Resume a session. VMark can suspend a shell process internally — it does so automatically as flow control when output arrives faster than the terminal can render it — but there is no user-facing control for it, and no session tab context menu to hang one on.
  • A blocking vmark --wait so $EDITOR can point at VMark (see Shell Environment above).
  • Scrollback persistence across restarts (see Persistence).
  • fish shell integration (see Shell integration).

Settings ​

Open Settings → Terminal to configure:

SettingRangeDefaultPlatforms
Panel Size10 % – 80 % of the available space, in 5 % steps40 %All
Font Size10 – 24 px13 pxAll
Line Height1.0 – 2.01.2All
Copy on SelectOn / OffOffAll
Automatic transcript renderingOn / OffOffAll
Mac Option as MetaOn / OffOnmacOS
Shell IntegrationOn / OffOnmacOS / Linux (zsh, bash)
Remote Clipboard (OSC 52)On / OffOnAll
Scrollback1,000 / 5,000 / 10,000 / 50,000 lines5,000All
Screen Reader ModeOn / OffOffAll

Automatic transcript rendering ​

Enable Automatic transcript rendering to display assistant Markdown, selectable tables and Mermaid diagrams in a rendered-transcript section inside the terminal area. It sits to the right of the CLI when the terminal is at the top or bottom, and below it when the terminal is on the left or right; the interactive CLI stays usable beside it.

The section starts collapsed. It opens by itself when a new reply contains a table or a Mermaid diagram — plain-text replies, which the terminal already shows well, leave it closed. Click the chart button in the terminal tab bar (tooltip Rendered Transcript) to show or hide it at any time; the button is highlighted while the transcript is shown, and hiding it gives the CLI the whole area back; after you collapse it, it stays closed until the next reply with a table or diagram. Content already in the transcript when the session is first shown does not open it. A hidden terminal stops reading transcripts.

Enabling adds a local SessionStart hook to Claude Code's settings.json and Codex's hooks.json, preserving existing hooks. Start or resume Claude/Codex in a VMark terminal after enabling; restart sessions that are already running. Codex may ask you to trust the new hook on its first run. Node and a CLI version with lifecycle hooks are required. Explicitly disabled or policy-restricted hooks, remote SSH sessions, and custom CLI configuration directories that differ from VMark's environment cannot provide a binding.

Each terminal follows its exact session rather than whichever transcript was modified most recently. The preview retains up to 100 assistant messages from the last 2 MiB of transcript data. Raw HTML and remote images remain inert; invalid diagrams remain readable as source. Disabling removes the rendered section and deactivates VMark's installed hooks.

Accessibility ​

SettingOptionsDefault
Terminal bellOff / Visual / AudibleVisual
Minimum contrastOff / WCAG AA (4.5:1) / WCAG AAA (7:1) / MaximumWCAG AA (4.5:1)

Most changes apply immediately to every open session — panel size and position, font size, line height, cursor, Copy on Select, Mac Option as Meta, Scrollback, Screen Reader Mode, Terminal bell and Minimum contrast. Shell, the WebGL renderer (not available on Linux), Remote Clipboard and Shell Integration are fixed when a session starts, so they apply to sessions opened afterwards. Panel Size goes up to 80 % of the available space. The editor keeps a minimum size in pixels, so it never disappears entirely no matter how large the terminal gets. Double-click the resize handle to jump straight to the maximum and back again without changing the stored size. Mac Option as Meta routes the macOS Option key as Meta in the integrated terminal so emacs, tmux, and similar tools see Alt-prefixed shortcuts (macOS only); it is on by default, so Option+Arrow does word movement rather than inserting accented characters. Shell Integration is available on macOS and Linux (hidden on Windows). Remote Clipboard is write-only (reads are always refused) and is described below. Scrollback controls how many lines of output each session retains in its scroll history — higher values use more memory. Screen Reader Mode exposes terminal output to assistive technology such as VoiceOver; it is off by default for performance. Terminal bell chooses how a bell (BEL) is signalled — a visual background-activity mark on the session tab, a soft audible beep (which also flags a background session's tab so you can find it), or nothing. Minimum contrast lifts faint terminal text to a readable contrast ratio against its background; raise it for accessibility or set it to Off to disable the lift.

Terminal font family

The terminal uses the Mono Font from Settings → Editor, not a font of its own, so changing it there restyles code blocks, Source mode and the terminal together. On Linux the System Default option follows your desktop's own monospace font, which is what your system terminal uses.

Font size and zoom

The terminal's font size is deliberately independent of the editor's reading size: a terminal is a dense monitoring surface, and its 13 px default matches what standalone terminals ship rather than the 18 px reading default. Mod + = / Mod + - zoom in steps of 2 px, so the terminal font can land on a value the dropdown doesn't list (13 → 15 → 17 …). The dropdown shows whatever size is actually in effect, adding the zoomed value to the list rather than snapping you back to a preset.

Remote clipboard (OSC 52) ​

Copy inside an ssh session, inside tmux, or in a remote editor, and the text lands on your clipboard — not the remote machine's. Programs request this by printing an OSC 52 escape sequence; VMark routes it to the system clipboard.

bash
# From anywhere the terminal can print — including over ssh:
printf '\e]52;c;%s\a' "$(printf 'hello' | base64)"

Writes only — reads are always refused

OSC 52 also defines a way to read the clipboard, and VMark never answers it, even with this setting on. Any process that can print bytes to your terminal could ask — including cat on a file you did not write — and the answer would arrive as if you had typed it. iTerm2 and VS Code refuse for the same reason. The setting controls writes; reads are refused unconditionally.

Turn Settings → Terminal → Remote Clipboard off to close the channel entirely. The change applies to newly spawned sessions.

Shell integration ​

When Shell Integration is on, VMark injects lightweight command markers into the shell so the terminal understands where each command starts and ends. It unlocks:

  • Prompt navigation — Cmd + ↑ / Cmd + ↓ jumps to the previous / next command prompt in the scrollback.
  • Exit-status decorations — a thin gutter bar marks each command line green (success) or red (failure).
  • Live working-directory tracking — relative file paths in output resolve against the shell's current directory, and new terminals open there.

zsh and bash are supported, on macOS and Linux. In both cases the injection is non-destructive — your real config is sourced first, and VMark's hooks are appended rather than substituted, so your prompt, theme, and aliases are untouched.

ShellHow VMark hooks inWhat it preserves
zshZDOTDIR points at a generated .zshrc that sources yours, then registers hooks with add-zsh-hookA custom $ZDOTDIR is honored: VMark resolves your real one from a login shell and sources .zshenv and .zshrc from there, not just $HOME
bashbash --rcfile <generated>, which sources ~/.bashrc firstAn existing PROMPT_COMMAND and an existing DEBUG trap are both composed with, not replaced — so bash-preexec, direnv, and atuin keep working

Because the terminal runs an interactive non-login shell, login-only files (.zprofile, .bash_profile, .profile) are out of scope for both shells, matching how a normal terminal tab behaves.

fish is not yet integrated; it runs normally without these features. Turn the setting off to disable injection entirely. Changes apply to newly spawned sessions (restart the terminal to apply).

Persistence ​

Whether the terminal panel is open is saved and restored across hot-exit restarts. Its size is the Panel Size setting — a share of the window that dragging the resize handle updates — so it is kept with your settings and survives every restart, whichever side the panel is on. Shell processes themselves cannot be preserved — a fresh shell is spawned for each session on restart. Scrollback is not preserved either: restoring it would mean writing whatever passed through your terminal (API keys included) to disk, so it is deliberately left for a design that addresses that first.