# Configuration Reference > 简体中文 | English All Lumina Terminal settings live in a single JSON file (`config.json`). The in-app Settings UI (`Ctrl/Cmd + ,`) covers most of them; this reference also lists fields that are **config-file-only** (marked *no UI*) and fields the app writes itself at runtime (marked *runtime-written*) that you normally shouldn't touch. > **Quit Lumina completely before editing config.json.** While the app is running it writes its in-memory config back to the file at any time (e.g. when you move the window or open a profile), which would overwrite your manual edits. ## Contents - [1. Config file location](#1-config-file-location) - [2. File structure](#2-file-structure) - [3. Global settings (GlobalConfig)](#3-global-settings-globalconfig) - [4. Profiles (profiles)](#4-profiles-profiles) - [5. Render options (TerminalRenderOptions)](#5-render-options-terminalrenderoptions) - [6. Theme files (themePath / theme)](#6-theme-files-themepath--theme) - [7. Key bindings (bindings)](#7-key-bindings-bindings) - [8. Command icon rules (commandIcons)](#8-command-icon-rules-commandicons) - [9. Wrap as App (profiles[].launcher)](#9-wrap-as-app-profileslauncher) - [10. Full example](#10-full-example) - [11. Related files](#11-related-files) --- ## 1. Config file location | OS | Path | |----|------| | Linux | `~/.local/share/com.iewnfod.lumina-terminal/config.json` | | macOS | `~/Library/Application Support/com.iewnfod.lumina-terminal/config.json` | | Windows | `%APPDATA%\com.iewnfod.lumina-terminal\config.json` | You can also see/open it in-app: **Settings → General → Developer → Config File Path**. ## 2. File structure The file has a single top-level key `"config"` and every setting is nested under it (this is the plugin-store format, not a typo): ```json { "config": { "language": "en-us", "profiles": [], "themeMode": "terminal" } } ``` - On load, keys present in the file override the built-in defaults; missing keys fall back to their defaults. Deleting a key restores its default. - Unknown keys are harmless but have no effect. ## 3. Global settings (GlobalConfig) ### Basics | Key | Type | Default | UI location | Description | |-----|------|---------|-------------|-------------| | `language` | `"en-us" \| "zh-cn"` | `"en-us"` | Settings → General → Basics | UI language. | | `autoUpdateOnStartup` | boolean | `true` | Settings → General → Basics | Check for updates on launch. | ### Appearance | Key | Type | Default | UI location | Description | |-----|------|---------|-------------|-------------| | `themeMode` | `"system" \| "terminal" \| "light" \| "dark"` | `"terminal"` | Settings → General → Appearance | How the app's light/dark *rendering* is decided (text, icons, glass, overlays). See below. | | `enableColorSpread` | boolean | `false` | Settings → General → Appearance | Color spread: when on, a fullscreen TUI's uniform background color "spreads" across the whole window chrome (sidebar, title bar, window background follow it); when off, the chrome keeps the terminal theme's background (edge sampling still runs in the background for the terminal's own seam-free interior fill — it just stops propagating outward). | | `windowOutline` | boolean | `true` | Settings → General → Appearance (Linux only) | Window outline: draw a 1px hairline around the window (color follows the terminal/TUI background) so the borderless window's edge stays visible on Linux desktop environments that add no compositor shadow. Never rendered on macOS/Windows — the flag has no effect there and the settings row is hidden. | | `edgeBackgroundCoverage` | number | `0.9` | **no UI** | Minimum share of the sampled outer edge cells one color must cover to be treated as the TUI background (remaining cells are edge-touching characters and are ignored). Valid range `(0, 1]`; `1` restores strict all-cells-uniform behavior. Invalid values fall back to the default. | **`themeMode` values** (the background *color* always follows the terminal / fullscreen TUI; this key only controls light/dark rendering of chrome): - `"system"` — follow the OS light/dark preference. - `"terminal"` — derive from the terminal background color (legacy default). - `"light"` / `"dark"` — force light / dark. When forced, even a fullscreen TUI cannot flip the window's appearance. ### Window | Key | Type | Default | UI location | Description | |-----|------|---------|-------------|-------------| | `rememberWindowPosition` | boolean | `false` | Settings → General → Window | Restore the main window's last position on startup (main window only; tear-off windows are positioned by their spawner). Not supported on Wayland; the toggle is grayed out there. | | `rememberWindowSize` | boolean | `false` | Settings → General → Window | Restore the main window's last size on startup. | | `rememberedWindowPosition` | `{x, y}` | — | **runtime-written** | Last main-window position (physical pixels). Written by the move listener while `rememberWindowPosition` is on; read once at startup. | | `rememberedWindowSize` | `{width, height}` | — | **runtime-written** | Last main-window size (physical pixels), same as above. | ### Tabs | Key | Type | Default | UI location | Description | |-----|------|---------|-------------|-------------| | `showTabBar` | boolean | `false` | Settings → General → Tabs | Show the sidebar tab list (also toggleable via shortcut or the `--sidebar` launch flag). | | `closeWindowOnLastTab` | boolean | `true` | Settings → General → Tabs | Close the window when the last tab closes. Set `false` to keep an empty window showing the profile quick-launch page (empty state). | | `inheritWorkingDirectory` | boolean | `false` | Settings → General → Behavior | New tabs inherit the **active** terminal's current working directory instead of the profile default, so you can hop between shells/profiles without re-`cd`-ing. Only affects newly created tabs; a window's first tab has no active terminal to inherit from and uses the profile default. | ### Sessions (save on exit / restore on launch) | Key | Type | Default | UI location | Description | |-----|------|---------|-------------|-------------| | `sessionSaveMode` | `"never" \| "always" \| "ask"` | `"ask"` | Settings → General → Sessions | What happens to open tabs when you quit. See below. | | `sessionSaveScrollback` | boolean | `false` | Settings → General → Sessions | Also serialize each terminal's scrollback into the saved session and replay it on restore. Can make session.json large. Only consulted when a save actually happens (`always`, or `ask` + user picks Save). | | `loadDefaultProfileOnStartup` | boolean | `true` | Settings → General → Sessions | Open a default-profile tab when starting with nothing to restore. Only applies when `sessionSaveMode` is `"never"`; with saving on, launches always try to restore a saved session first (first run seeds a default tab). | **`sessionSaveMode` values**: - `"never"` — never persist. - `"always"` — always save every terminal tab on window close and restore on next launch. - `"ask"` — prompt on close; the dialog's "remember this choice" rewrites this value to `always` or `never`. Saved sessions live in a separate `session.json` (see [Related files](#11-related-files)), never in config.json. ### Behavior | Key | Type | Default | UI location | Description | |-----|------|---------|-------------|-------------| | `imeDuplicateInputFix` | boolean | `true` | Settings → General → Behavior | IME duplicate-input fix: installs a guard on each terminal's hidden textarea that normalizes WebKitGTK/IBus commits arriving without a matching compositionstart, preventing duplicated CJK/IME input on Linux. The guard rewrites the textarea on each such commit, which can cost IME responsiveness on slower machines — turn it off if IME input feels sluggish (Linux/WebKitGTK may then duplicate input again). | | `autoProxy` | boolean | `true` | Settings → General → Behavior | Auto proxy sync: watches the system proxy (GNOME gsettings / KDE kioslaverc / macOS scutil / Windows registry) and keeps `http_proxy`, `HTTPS_PROXY`, … in sync inside every running bash/zsh/fish tab — applied silently by the shell-integration precmd hook before each prompt, no restart needed. Only values Lumina injected are ever unset; manually exported proxies are left alone. Shells without integration (nu/pwsh/SSH) are not touched. Turning it off stops the watcher and deletes the hooks' env file, so running shells drop (only) the values Lumina injected. | ### AI / MCP | Key | Type | Default | UI location | Description | |-----|------|---------|-------------|-------------| | `enableMcp` | boolean | `false` | Settings → General → Developer | Run a **read-only** MCP (Model Context Protocol) HTTP server on `127.0.0.1` so a local AI client can see open tabs, the foreground command, the live cwd, and recent output. There is deliberately no tool that writes to the PTY. | | `mcpPort` | number | `28700` | Settings → General → Developer | MCP server port (loopback only). Changing it applies after you toggle the server off and on. | ### Advanced (no UI — edit config.json) | Key | Type | Default | Description | |-----|------|---------|-------------| | `edgeBackgroundCoverage` | number | `0.9` | See Appearance above. | | `emptyStateMaxProfiles` | number | `0` (unlimited) | Max profiles the empty-state quick-launch list shows (most recently opened first; never-opened profiles keep their config order at the end). `0`/unset = show all. | | `profileLastOpened` | `Record` | — | **runtime-written**. Per-profile "last opened" timestamps driving the empty-state recency sort. Safe to delete (only loses the sort order). | ### Deprecated | Key | Description | |-----|-------------| | `copyWithCtrl` | Legacy "Ctrl+C copies" toggle, replaced by the user-bindable `copy` action. On startup a one-time migration converts `true` into a plain Ctrl+C `copy` binding and strips the field. **Do not write this key by hand.** | ## 4. Profiles (profiles) `profiles` is an array; each entry describes one terminal configuration (shell, appearance, startup behavior). Render fields inherit from `globalProfile` key by key (see [Render options](#5-render-options-terminalrenderoptions)). | Key | Type | Default | Description | |-----|------|---------|-------------| | `name` | string | (required) | Profile name, must be unique; also used as the identifier by the empty-state quick launch, MCP, launchers, etc. | | `type` | `"local" \| "remote"` | `"local"` | Local shell or SSH remote. | | `exePath` | string | required for local | Path to the local shell executable (e.g. `/bin/zsh`). Leave empty for remote profiles. | | `cwd` | string | unset = home directory | Startup directory. | | `default` | boolean | `false` | The default profile. Keep exactly one `true`; the first profile you create is marked default automatically. | | `startupCommand` | string | empty = interactive shell | Command to run on startup (e.g. `"vim"`). Locally executed as ` --login -i -c ""` (the shell exits when the command does); for SSH profiles it is passed to the remote host (`ssh user@host `). | | `keepAfterExit` | `"exit" \| "shell" \| "freeze"` | `"exit"` | What happens after `startupCommand` finishes — see below. Only meaningful when `startupCommand` is set. | | `ssh` | object | — | Connection parameters for remote profiles — see below. | | `launcher` | object | — | "Wrap as App" configuration, see [section 9](#9-wrap-as-app-profileslauncher). The object's presence enables the feature. | | (render options) | — | — | Any [render option](#5-render-options-terminalrenderoptions) (rows/cols/font/theme/padding/webgl/…) can be set per profile, overriding `globalProfile`. | **`keepAfterExit` values**: - `"exit"` (default) — the shell exits with the command and the tab closes. Ideal for single-shot launches (vim / opencode). - `"shell"` — after the command, `exec` into an interactive shell: you can read the output AND keep working; the tab closes only when that shell exits. - `"freeze"` — let the command + shell exit naturally, but the frontend suppresses the auto-close so the frozen output stays on screen for reading (read-only; the PTY is gone). Close it manually. **`ssh` object**: | Key | Type | Default | Description | |-----|------|---------|-------------| | `host` | string | (required) | Hostname / IP. | | `port` | number | `22` | Port. | | `user` | string | current user | Login user. | | `identityFile` | string | — | Private key path (passed as `ssh -i`). | The UI can import hosts from `~/.ssh/config` (Settings → Profiles → New Remote Profile → Import from .ssh/config). ## 5. Render options (TerminalRenderOptions) `globalProfile` (Settings → Global Profile) and each `profiles[]` entry share the same fields: **Inheritance**: every key present on a profile overrides the same key on `globalProfile`; missing keys use the global value; keys set nowhere use the built-in default. The terminal color palette (`theme`) merges specially — see [Theme files](#6-theme-files-themepath--theme). ### Lumina-specific options | Key | Type | Default | UI location | Description | |-----|------|---------|-------------|-------------| | `rows` / `cols` | number | — | Settings → Global Profile / Profiles | Initial rows/columns. Only the main window's first tab uses them to size the OS window; afterwards everything resizes freely. | | `padding` | number or object | — | Settings → Global Profile / Profiles | Terminal inner padding (px). A number applies to all sides; the object form `{x, y, left, right, top, bottom}` sets sides individually (`x` = left/right, `y` = top/bottom; the finer keys win). Note: to keep the first/last cells clear of the rounded corners, actual padding has a floor (left ≥ 7, others ≥ 5); maximized windows add the system safe-area inset on top. The UI only edits the number form; use config.json for the object form. | | `webgl` | boolean | `false` | Render Settings | Use the WebGL renderer for GPU-accelerated drawing. | | `graphemeClusters` | boolean | `false` | Render Settings | Experimental: grapheme-cluster width rules, so complex emoji (ZWJ sequences, combining marks) measure correctly, at higher CPU cost. Supersedes the Unicode 11 width table when on. | | `ligatures` | boolean | `false` | Render Settings | Programming ligatures. The backend reads the font file named by `fontFamily` and parses its GSUB table for precise, font-specific ligatures (Fira Code's `www`, `//`, …); falls back to a built-in list of ~50 common ligatures when the font can't be found. Pair with a ligature font (Fira Code, JetBrains Mono, …). | | `fontStyle` | `"normal" \| "italic"` | `"normal"` | Render Settings | Font style. | | `themePath` | string | — | Render Settings | Path to a theme JSON file — see [Theme files](#6-theme-files-themepath--theme). | | `theme` | object | — | **no UI** | Inline theme (partial ITheme), same format as a theme file; takes precedence over `themePath`. | ### xterm.js passthrough options `TerminalRenderOptions` extends xterm.js's `ITerminalOptions` directly, so every option below (and any other xterm.js option) can be written on `globalProfile` or a profile. Defaults are xterm.js built-ins. | Key | Type | xterm default | Description | |-----|------|---------------|-------------| | `fontFamily` | string | platform monospace stack | Font family, e.g. `"JetBrains Mono"`. The ligature feature locates the font file through it. | | `fontSize` | number | `15` | Font size (px). | | `fontWeight` | `"normal" \| "bold" \| "100"…\|"900"` | `"normal"` | Weight for normal text. | | `fontWeightBold` | same | `"bold"` | Weight for bold text. | | `letterSpacing` | number | `0` | Letter spacing (whole pixels). | | `lineHeight` | number | `1.0` | Line height multiplier. | | `scrollback` | number | `1000` | Scrollback lines. With session scrollback saving (`sessionSaveScrollback`) this is also the amount replayed on restore. | | `cursorStyle` | `"block" \| "underline" \| "bar"` | `"block"` | Cursor shape. | | `cursorBlink` | boolean | `false` | Cursor blinking. | | `cursorWidth` | number | `1` | Width of the `bar` cursor (px). | | `cursorInactiveStyle` | `"outline" \| "block" \| "bar" \| "underline" \| "none"` | `"outline"` | Cursor style when unfocused. | | `customGlyphs` | boolean | `true` | Draw built-in glyphs for block/box-drawing characters instead of font glyphs (better line continuity). | | `drawBoldTextInBrightColors` | boolean | `true` | Render bold text in bright colors. | | `minimumContrastRatio` | number | `1` | Minimum contrast ratio; > 1 dynamically adjusts foreground colors for readability. | | `allowTransparency` | boolean | `false` | Allow non-opaque background colors. Must be set before `open()`; can hurt performance. | | `altClickMovesCursor` | boolean | `true` | Alt+click moves the prompt cursor to the click position. | | `convertEol` | boolean | `false` | Treat `\n` as `\r\n` (the PTY's termios normally handles this — don't enable casually). | | `fastScrollSensitivity` | number | `5` | Fast-scroll multiplier while Alt is held. | | `scrollSensitivity` | number | `1` | Mouse wheel scroll speed multiplier. | | `smoothScrollDuration` | number | `0` | Smooth scroll duration (ms), `0` = off. | | `tabStopWidth` | number | `8` | Tab stop width. | | `wordSeparator` | string | common punctuation set | Characters that break double-click word selection. | | `scrollOnUserInput` | boolean | `true` | Scroll to bottom on user input. | | `scrollOnEraseInDisplay` | boolean | `false` | Scroll when receiving an `ED` (erase-in-display) sequence. | | `rightClickSelectsWord` | boolean | `false` | Right-click selects the word under the cursor (macOS convention). | | `rescaleOverlappingGlyphs` | boolean | `false` | Rescale overlapping glyphs. | | `reflowCursorLine` | boolean | `false` | Reflow the cursor's line on resize (shells usually handle this themselves). | | `screenReaderMode` | boolean | `false` | Screen reader support (NVDA/VoiceOver). | | `disableStdin` | boolean | `false` | Disable keyboard input. | | `ignoreBracketedPasteMode` | boolean | `false` | Ignore bracketed paste mode. | | `macOptionIsMeta` | boolean | `false` | Treat Option as Meta on macOS. | | `macOptionClickForcesSelection` | boolean | `false` | Option+click forces selection on macOS. | ## 6. Theme files (themePath / theme) **Path resolution**: `themePath` is resolved **relative to the app data dir first** (`themes/my-theme.json` → `/themes/my-theme.json`), then tried as-given (absolute path). A theme file is JSON containing any subset of the keys below: ```json { "background": "#1e1e2e", "foreground": "#cdd6f4", "cursor": "#f5e0dc", "selectionBackground": "rgba(180, 190, 254, 0.3)", "red": "#f38ba8", "brightBlue": "#89b4fa" } ``` **Merge order** (later overrides earlier; all layers may be partial): 1. Built-in fallback — GitHub Light when the OS is light, the classic black theme otherwise (and when unresolved); 2. `globalProfile`'s `themePath` / `theme` (when a global profile exists); 3. the profile's own `themePath`; 4. the profile's own inline `theme`. **Available color keys**: | Category | Keys | |----------|------| | Basic | `background` `foreground` `cursor` `cursorAccent` | | Selection | `selectionBackground` `selectionForeground` `selectionInactiveBackground` | | Scrollbar | `scrollbarSliderBackground` `scrollbarSliderHoverBackground` `scrollbarSliderActive` | | Standard 16 | `black` `red` `green` `yellow` `blue` `magenta` `cyan` `white` | | Bright 16 | `brightBlack` `brightRed` `brightGreen` `brightYellow` `brightBlue` `brightMagenta` `brightCyan` `brightWhite` | | Extended | `extendedAnsi` (256-color array) | Color format: `#rgb` / `#rrggbb` hex; the selection keys also accept translucent `rgba(...)`. ## 7. Key bindings (bindings) `bindings` is an array, one entry per shortcut: ```json { "key": "t", "with": ["CtrlOrCommand"], "action": "newTab" } ``` | Field | Description | |-------|-------------| | `key` | The keyboard event's `key` value. Single-character keys match case-insensitively (`"p"` matches the `"P"` produced by Shift+p). | | `with` | Modifier array: `"ctrl"` `"shift"` `"alt"` `"command"` (macOS Cmd) `"CtrlOrCommand"` (Cmd on macOS, Ctrl elsewhere). The UI requires at least one modifier; keep at least one in hand-written entries too. | | `action` | Action name — see below. | | `args` | Optional argument object — see below. | **Merge rule**: unset/empty `bindings` = all defaults. When set, your entries **replace the default entry with the same action + args**; defaults whose action is not covered remain active (e.g. a custom `newTab` replaces the default `Ctrl/Cmd+T`, but the `toTab` entries stay). Restore defaults by deleting the `bindings` field. **Actions**: | Action | Args | Description | |--------|------|-------------| | `newTab` | `{profileName: "name"}` (optional) | New tab; with `profileName` uses that profile, without uses the default. | | `closeTab` | — | Close the current tab. | | `toTab` | `{index: "0"…}` | Switch to tab by index; `"last"` for the last one. | | `toggleSidebar` | — | Show/hide the sidebar. | | `tearOffTab` | — | Tear the current tab into its own window (keeps the process and scrollback). | | `search` | — | In-terminal search (the Ctrl+F bar). | | `copy` | — | Copy the current selection. Special: **with no selection the key falls through to the shell** — so binding copy to Ctrl+C never breaks SIGINT. | | `paste` | — | Paste the clipboard into the terminal. | | `selectAll` | — | Select the whole terminal buffer. | | `openSettings` | — | Open Settings. | | `openConfigFile` | — | Open config.json with the system editor. | | `openCommandPalette` | — | Open the command palette. | **Default bindings**: | Shortcut | Action | |----------|--------| | `Ctrl/Cmd + T` | New tab (default profile) | | `Ctrl/Cmd + W` | Close current tab | | `Ctrl/Cmd + ,` | Open Settings | | `Ctrl/Cmd + Shift + P` | Command palette | | `Ctrl/Cmd + 1…8` | Switch to tab 1…8 | | `Ctrl/Cmd + 9` | Switch to last tab | | `Ctrl/Cmd + Shift + L` | Tear off current tab | | `Ctrl/Cmd + F` | Find in terminal | | `Ctrl/Cmd + Shift + C` | Copy selection | | `Ctrl/Cmd + Shift + A` | Select all | | `Ctrl/Cmd + Shift + V` | Paste | > Plain `Ctrl/Cmd + V` is deliberately not intercepted: quoted-insert in readline and the browser-native paste keep working as always. ## 8. Command icon rules (commandIcons) The tab icon follows the running foreground command via a built-in mapping (`opencode`, `vim`/`nvim`/`neovim`, `claude` → their app icons; wrapper commands like `sudo`/`env`/`watch` are skipped to find the real command). The `commandIcons` array adds your own rules — **evaluated in order before the built-in table, first match wins**, so rules can override built-ins: ```json { "commandIcons": [ { "match": "cargo", "icon": "custom:rust.png" }, { "match": "^git\\s+push", "isRegex": true, "icon": "neovim" } ] } ``` | Field | Description | |-------|-------------| | `match` | When `isRegex` is `false` (default): a **command name** (basename) compared exactly against the first non-wrapper token of the command line (case-insensitive, `.exe` stripped). When `true`: a **JavaScript regex source** tested against the whole raw command line, so arguments can participate (`^git\s+push`). | | `isRegex` | boolean, default `false`. | | `icon` | Icon id: a built-in app icon (`opencode` `vim` `neovim` `claudecode` today) or `custom:` — an image imported via Settings → Command Icons → "Import image…" (stored under the app data dir's `command-icons/`). | UI: **Settings → Command Icons**, with a live test preview; saving prunes imported images no rule references. ## 9. Wrap as App (profiles[].launcher) Adding a `launcher` object to a profile enables "Wrap as App": on every config save the app generates a desktop launcher (Linux `.desktop` / macOS `.app` / Windows Start-Menu shortcut) that opens the profile in its own window (via the app's `--profile` launch flags). Deleting a profile auto-prunes its launcher on the next save. | Key | Type | Default | Description | |-----|------|---------|-------------| | `title` | string | profile name | Launcher display name + window title. | | `workingDirectory` | string | the profile's `cwd` | Overrides the startup directory. | | `sidebar` | `"show" \| "hide"` | `"hide"` | Sidebar visibility of the launched window. | | `icon` | string | auto | Icon: derived automatically from `startupCommand` (the `lib/appIcon.ts` mapping), falling back to the app's own icon; may also be a built-in icon id or `custom:`. | UI: **Settings → Profiles → pick a profile → Wrap as App**, including the generated launcher's location with a reveal button. ## 10. Full example A config.json touching most fields (omit keys you don't need): ```json { "config": { "language": "en-us", "themeMode": "system", "enableColorSpread": true, "windowOutline": true, "edgeBackgroundCoverage": 0.95, "showTabBar": true, "closeWindowOnLastTab": false, "inheritWorkingDirectory": true, "rememberWindowPosition": true, "rememberWindowSize": true, "sessionSaveMode": "always", "sessionSaveScrollback": false, "loadDefaultProfileOnStartup": true, "imeDuplicateInputFix": true, "autoProxy": true, "autoUpdateOnStartup": true, "enableMcp": true, "mcpPort": 28700, "emptyStateMaxProfiles": 6, "globalProfile": { "fontFamily": "JetBrains Mono", "fontSize": 14, "ligatures": true, "webgl": true, "scrollback": 10000, "cursorBlink": true, "cursorStyle": "bar", "padding": 10, "themePath": "themes/catppuccin-mocha.json" }, "profiles": [ { "name": "zsh", "exePath": "/bin/zsh", "cwd": "/home/user", "default": true, "padding": { "x": 12, "y": 8 } }, { "name": "dev server", "exePath": "/bin/bash", "startupCommand": "npm run dev", "keepAfterExit": "freeze", "fontSize": 13 }, { "name": "my server", "type": "remote", "ssh": { "host": "203.0.113.10", "port": 22, "user": "root", "identityFile": "/home/user/.ssh/id_ed25519" } }, { "name": "opencode", "exePath": "/bin/zsh", "startupCommand": "opencode", "launcher": { "title": "OpenCode", "sidebar": "hide", "icon": "opencode" } } ], "bindings": [ { "key": "t", "with": ["CtrlOrCommand"], "action": "newTab" }, { "key": "1", "with": ["CtrlOrCommand", "shift"], "action": "toTab", "args": { "index": "0" } } ], "commandIcons": [ { "match": "bottom", "icon": "custom:lazydocker.png" } ] } } ``` ## 11. Related files | File / directory | Description | |------------------|-------------| | `config.json` | Everything documented here. | | `session.json` | Saved terminal session (tab list + optional scrollback), driven by `sessionSaveMode`, kept separate from config.json. | | `themes/` | Recommended home for theme JSON files (under the app data dir; the first location relative `themePath`s resolve against). | | `command-icons/` | Imported custom command / launcher icons. | | launchers | "Wrap as App" output: Linux `~/.local/share/applications/` (`lumina-` prefixed), macOS `~/Applications/`, Windows Start Menu `Programs/Lumina/`. | The app data dir is the directory config.json lives in ([section 1](#1-config-file-location)).