lazyshell

Configuration

lazyshell config init writes a fully commented config file at the right place, and lazyshell config show prints the configuration actually in effect — after every layer has had its say — together with the sources it came from. That second command is the answer to "why is my setting not taking".

lazyshell config edit opens that file in your editor — $VISUAL, else $EDITOR, else the first of nano, vim, vi that is installed — creating it from the commented template first if it does not exist yet. When the editor exits, the saved file is re-read and anything wrong with it (an unknown key, an out-of-range value, an unparseable keybinding) is reported straight away rather than at the next start.

Where the file lives

lazyshell reads its YAML config file from the first match:

  1. $LAZYSHELL_CONFIG, if set
  2. $XDG_CONFIG_HOME/lazyshell/config.yml
  3. ~/.config/lazyshell/config.yml

A missing file is not an error — lazyshell just runs with its built-in defaults. A partial file only needs to mention the fields it wants to override; everything else keeps its default.

Precedence

built-in defaults  <  ~/.config/lazyshell/config.yml  <  project lazyshell.yml
                   <  environment variables  <  command-line flags

Nothing in a config file can stop lazyshell from starting. A key it does not know, a value out of range, an unparseable keybinding or an unknown colour are each reported on stderr before the interface opens, and the built-in default is used instead — never a silent no-op, never a refusal to run.

Option reference

KeyTypeDefaultEffect
languagefr | enfrUI language: bindings, popups, status bar, footers and session messages. CLI output (lazyshell config …) stays French.
shellstring""Command started behind each session's pty. Empty means $SHELL, falling back to /bin/bash.
termstringxterm-256colorTERM announced to sessions. Lower it to make programs degrade on purpose.
scrollback_sizeint ≥ 010000Lines kept per session once they scroll off-screen.
sessions_panel_widthint ≥ 540Sessions list width, in columns, in landscape mode.
sessions_panel_heightint ≥ 510Sessions list height, in rows, in portrait mode.
agents_panel_heightint ≥ 36Agents dashboard height, in rows, under the sessions panel in landscape mode. Hidden automatically when no AI agent session is detected, and in portrait mode.
portrait_max_widthint84Portrait mode applies at or below this terminal width…
portrait_min_heightint45…and above this terminal height. Portrait stacks the panels instead of splitting them side by side.
refresh_interval_msint, 10–100030Redraw period. An unchanged panel is never pushed, so idle cost stays near zero at any value.
kill_timeout_msint ≥ 1002000Wait after SIGTERM before escalating to SIGKILL, and again before giving up.
prefix_keykey specCtrl+OLocks the panel: one press, out of pass-through. Must be a control key, and it can no longer be typed into a session. $LAZYSHELL_PREFIX overrides it.
keybindingsmapsee belowRemaps an action id to a key spec. An action left out keeps its default key.
markers.bell0–1 char!Gutter marker for a session that rang while hidden. "" turns it off.
markers.alt_screen0–1 char#Gutter marker for a session running a full-screen application.
markers.activity0–1 charGutter marker for a session that produced output while hidden.
markers.broadcast0–1 char+Gutter marker for a session marked to receive broadcast keystrokes.
markers.agent_idle0–1 charGutter marker for a detected AI agent session that is idle.
markers.agent_working0–1 charGutter marker for a detected AI agent session that is working.
markers.agent_blocked0–1 charGutter marker for a detected AI agent session waiting on you.
markers.agent_done0–1 charGutter marker for a detected AI agent session that finished its turn.
markers.agent_idle_colorcolourgreenColour for markers.agent_idle.
markers.agent_working_colorcolouryellowColour for markers.agent_working. Pulses between full and dimmed brightness (twice a second) while the agent is working — the only one of the four states that animates.
markers.agent_blocked_colorcolourredColour for markers.agent_blocked.
markers.agent_done_colorcolourblueColour for markers.agent_done.
markers.command_failed0–1 charMarker (next to its exit code, in the name/status columns rather than the gutter) for a non-agent session whose last command — per shell-integration OSC 133 — exited non-zero.
markers.restart0–1 charMarker (next to its attempt count, in the name/status columns rather than the gutter) for a session that has needed at least one automatic restart — see restart:.
scroll.page_linesint ≥ 00Lines PgUp/PgDn move by. 0 means one full panel height.
scroll.half_page_divisorint ≥ 12Ctrl+U/Ctrl+D move by the panel height divided by this.
theme.active_border_colorcolourgreenFocused panel's border.
theme.inactive_border_colorcolourdefaultEvery other panel's border.
theme.selected_bg_colorcolourblueSelected line's background in the sessions list.
theme.locked_border_colorcolourredOutput panel's border while locked (i.e. not in pass-through).
theme.tab_active_colorcolourgreenSelected tab in the output panel's tab strip.
clipboard.fallback_commandstring""Command run with the yanked text on its stdin, instead of OSC 52, for a terminal that does not support it. There is no way to detect support, so this is a manual switch: empty means OSC 52 only.
notify.fallback_commandstring""Command run with the notification text on its stdin, instead of OSC 9/777, when a detected AI agent session goes blocked or done. Empty means OSC only.
window_title.enabledbooltrueWhether the host terminal's window/tab title tracks the focused session (its name, plus its live OSC 0/2 title when one is set) via OSC 0.
mouse.enabledbooltrueClick, wheel and drag support. Turning it on costs Shift+↑/Shift+↓ pass-through — gocui gives those keys and the mouse buttons the same values, so they cannot both work.
mouse.wheel_linesint ≥ 13Lines one wheel notch scrolls the output panel by.
mouse.forward_to_appbooltrueWhether a program inside a session may receive the mouse itself, and only once it has asked for it with a DECSET 9/1000/1002/1003 (vim with set mouse=a, htop). A shell or an AI agent CLI never asks.
perf.refresh_interval_ms0, or int ≥ 1005000How often every session's processes are sampled for the resources tab. Runs in the background whether or not the tab is open, in a single pass across all sessions. 0 turns sampling off — it is the one periodic job that spawns a process.
env_tab.mask_secretsbooltrueWhether the environment tab masks the value of variables whose name looks like a credential (TOKEN, SECRET, PASSWORD, AUTH, ..._KEY).
control.enabledboolfalseWhether the agent control API is open — the socket lazyshell ctl drives a running lazyshell over. Off by default; read the agent sessions page before turning it on, since it lets any process running as you create sessions, type into them and read their output.
agent_stats_commandstring""Run for the selected AI agent session, with $LAZYSHELL_SESSION_ID in its environment; its first line of stdout is shown next to the turn duration. Empty disables it.
restore_layoutask | always | neveraskWhat to do, at launch, with a saved session layout for the current directory (see layout persistence) when there is no lazyshell.yml: ask shows a confirmation popup, always restores it with no prompt, never never offers it.

Key specs

Key specs use gocui.Parse syntax: a bare character (n), or Ctrl+N, Alt+Space, Tab, Esc.

The remappable action ids are:

new_session, new_named_session, new_session_in_dir, kill_session, delete_session, rename_session, duplicate_session, restart_session, zoom, next_tab, prev_tab, filter_sessions, export_session, toggle_broadcast, jump_next_blocked, jump_prev_prompt, jump_next_prompt, copy_last_output, arm_watch, set_group, filter_group, broadcast_group, kill_group, restart_group, toggle_debug, select_next, select_prev, cycle_focus, help, quit.

An id outside that list is reported rather than ignored.

Colours

Colours accept any of:

The two name sets overlap and disagree: in CSS, blue is #0000FF, which a terminal shows as bright blue. lazyshell resolves the ANSI names first, so blue gives you ordinary blue; write navy if you want the CSS one, or brightblue for the bright terminal slot.

Full example

This is what lazyshell config init writes — every option at its default value, so you can delete whatever you do not change.

# ~/.config/lazyshell/config.yml

language: fr
shell: ""
term: xterm-256color
scrollback_size: 10000

sessions_panel_width: 40
sessions_panel_height: 10
agents_panel_height: 6
portrait_max_width: 84
portrait_min_height: 45

refresh_interval_ms: 30
kill_timeout_ms: 2000

prefix_key: Ctrl+O

keybindings:
  new_session: "n"
  new_named_session: "N"
  new_session_in_dir: "M"
  kill_session: "x"
  delete_session: "D"
  rename_session: "r"
  duplicate_session: "c"
  restart_session: "R"
  zoom: "z"
  next_tab: "]"
  prev_tab: "["
  filter_sessions: "/"
  export_session: "w"
  toggle_broadcast: "b"
  jump_next_blocked: "B"
  jump_prev_prompt: "{"
  jump_next_prompt: "}"
  copy_last_output: "Y"
  arm_watch: "v"
  set_group: "g"
  filter_group: "G"
  broadcast_group: "A"
  kill_group: "X"
  restart_group: "W"
  toggle_debug: F12
  select_next: "j"
  select_prev: "k"
  cycle_focus: Tab
  help: "?"
  quit: "q"

markers:
  bell: "!"
  alt_screen: "#"
  activity: "●"
  broadcast: "+"
  agent_idle: "●"
  agent_working: "●"
  agent_blocked: "●"
  agent_done: "●"
  agent_idle_color: "green"
  agent_working_color: "yellow"
  agent_blocked_color: "red"
  agent_done_color: "blue"
  command_failed: "✗"
  restart: "↻"

scroll:
  page_lines: 0
  half_page_divisor: 2

theme:
  active_border_color: green
  inactive_border_color: default
  selected_bg_color: blue
  locked_border_color: red
  tab_active_color: green

clipboard:
  fallback_command: ""

notify:
  fallback_command: ""

window_title:
  enabled: true

mouse:
  enabled: true
  wheel_lines: 3
  forward_to_app: true

perf:
  refresh_interval_ms: 5000

env_tab:
  mask_secrets: true

control:
  enabled: false

agent_stats_command: ""

restore_layout: ask