Skip to content

Interactive Features

~/.lash/
config # shell configuration
history # aggregated command usage
sessions/ # one file per session, timestamped
plugins.conf # external plugin registration
plugins/ # native `.lash` plugins + external plugin sockets
profiles/ # security profile files
audit.log # audit log
audit.key # audit key file
lashd.sock # daemon socket
lashd.pid # daemon PID

Any *.lash file in ~/.lash/plugins/ is auto-loaded on session startup — its fn and type declarations are registered into the session scope. See Writing your first .lash plugin.

On interactive startup, lash reads ~/.lash/config. This file can contain:

  • Variable declarations (let/mut)
  • Aliases
  • Function definitions
  • Prompt configuration
  • Hook configuration
  • Environment variable overrides
  • Profile and audit settings

For non-interactive (script) execution, ~/.lash/config is not loaded. Scripts run in a clean environment with only inherited environment variables.

mut PROMPT = "$PWD > "
mut PROMPT = "${PWD.split("/").last} > "
alias ll = `ls -la`
alias gs = `git status`

Aliases expand in command position only. Typically stored in ~/.lash/config.

History is an aggregated index sorted by usage frequency, not a chronological log. Each entry tracks:

  • Command text
  • Usage count
  • Last used timestamp
  • Average execution time

New commands increment existing entries rather than appending duplicates.

History is queryable via functional chains:

history.filter(h => h["cmd"].contains("docker")).sort(h => h["count"]).reverse

Every interactive session is recorded in ~/.lash/sessions/ as a timestamped JSONL file containing commands, exit codes, error output, and working directory.

Context-aware completion:

  • Command position: binary names from PATH, user functions (fn declarations, including those from .lash plugins), built-ins.
  • Argument position (typed parameters): user-defined types with a values(query) method feed suggestions live. gco <Tab> pulls git branches through GitBranch.values(); results are cached per (type, query) for the type’s declared TTL.
  • After backtick-dot: built-in methods.
  • After .json + bracket: JSON keys (if known from previous run).
  • File paths: file and directory names.
  • History-informed: frequent commands rank higher.

lash can load existing zsh completion definitions from standard locations (/usr/share/zsh/site-functions/, ~/.zsh/completions/) as a fallback. Native lash completions take priority.

See Defining a custom type for completion for how values(query), validate(x), and the cache = <duration> directive fit together.

The interactive line editor handles multi-line input. A literal newline (pasted, or accepted while a brace, quote, or heredoc is still open) extends the buffer to a new visual row. Edits redraw only the affected region to avoid flicker on long input.

Press Ctrl-R to open the reverse-incremental search overlay. As you type, lash matches your buffer as a substring against history entries and shows the best match inline. Ctrl-R again cycles to the next match, Enter accepts, Esc cancels.

Interactive UI is layered over the prompt as a stack of overlays. The topmost overlay receives key events first; pressing Esc pops it.

OverlayPurpose
Selection (completion)Tab-completion picker. Up/down navigates, Tab/Enter accepts, Esc dismisses.
History previewShows a candidate command from history before you accept it.
History searchReverse-incremental search (Ctrl-R).
Permission requestModal prompt when a plugin or sandbox check needs user approval.

While running interactively, lash sets the terminal window title to the command you’re executing. The title is taken from the first token of the command line and truncated for display; control bytes are stripped before being emitted.

When a foreground command is running:

  • Ctrl-C (SIGINT) and Ctrl-Z (SIGTSTP) update the job state and return control to the shell instead of leaking through to the parent.
  • A stopped foreground job resumed with fg re-attaches the controlling PTY so it can receive keystrokes again.
  • PTY input filters out signal bytes before re-injecting them, so a single keypress doesn’t generate two signals.

The bundled highlight plugin colorizes the input line in real time. Colors are driven by named themes loaded from the plugin configuration; the default theme covers commands, strings, variables, operators, comments, and backtick captures with distinct foreground colors.